Echelon, LONWORKS,LONMARK,NodeBuild er, LonTalk,Neuron,
3120, 3150, ShortStack, LonMaker, and the Echelon logo are
trademarks of Echelon Corporation registered in the United
States and other countries. 3170 is a trademark of the
Echelon Corporation.
Other brand and product names are trademarks or
registered trademarks of their respective holders.
Neuron Chips and other OEM Products were not designed
for use in equipment or systems, which involve danger to
human health or safety, or a risk of property damage and
Echelon assumes no responsibility or liability for use of the
Neuron Chips in such applications.
Parts manufactured by vendors other than Echelon and
referenced in this document have been described for
illustrative purposes only, and may not have been tested
by Echelon. It is the responsibility of the customer to
determine the suitability of these parts for each
application.
ECHELON MAKES AND YOU RECEIVE NO WARRANTIES OR
CONDITIONS, EXPRESS, IMPLIED, STATUTORY OR IN ANY
COMMUNICATION WITH YOU, AND ECHELON SP ECIFICALLY
DISCLAIMS A N Y IMPLIED WARR A N T Y OF M ER C H ANTABILITY
OR FITNESS FOR A PARTICULAR PURPOSE.
No part of this publication may be reproduced, stored in a
retrieval s ystem, or transmitted, in any form or by any means,
electronic, mechanical, photocopying, recording, or
otherwise, without the prior written permission of Echelon
Corporation.
This guide describes how to write programs using the Neuron® C Version 2.2
language. Neuron C is a programming language based on ANSI C that is
designed for Neuron Chips and Smart Transceivers. It includes network
communication, I/O, and event-handling extensions to ANSI C, which make it a
powerful tool for the development of L
programming with Neuron C are explained through the use of specific code
examples and diagrams. A general methodology for designing and implementing
ONWORKS application is also presented.
a L
A subset of the Neuron C language is also used to describe the interoperable
interface of host-based applications that are designed with the ShortStack®
Developer’s Kit, FTXL™ Developer’s Kit, or the
interoperable interface is contained within a file called a
contains Neuron C declarations and definitions for the device interface. In
addition to describing the Neuron C Version 2.2 language, this guide also
provides a brief introduction to model file compilation, and points out syntactical
differences between compilation for Neuron-hosted devices and compilation for
host-based devices that use a model file.
ONWORKS
®
applications. Key concepts in
i
.LON® SmartServer. This
model file
, which
The Neuron C Programmer’s Guide
• Outlines a recommended general approach to developing a L
• Explains key concepts of programming in Neuron C through the use of
Audience
The
Neuron C Programmer’s Guide
are developing L
familiar with the ANSI C programming language, and have some C programming
experience.
For a complete description of ANSI C, consult the following references:
• —. 1989.
• —. 2007.
• Harbison, Samuel P. and Guy L. Steele, Jr. 2002.
:
application, and
code fragments and examples.
is intended for application programmers who
ONWORKS applications. Readers of this guide are assumed to be
American National Standard for Information Systems
Programming Language C
NY: American National Standards Institute.
. Standard number X3.159-1989. New York,
International Standard ISO/IEC 9899:1999. Programming
languages – C
Standardization.
Manual
. Geneva, Switzerland: International Organization for
, 5th edition. Upper Saddle River, NJ: Prentice Hall, Inc.
ONWORKS
C: A Reference
•Kernighan, Brian W. and Dennis M. Ritchie. 1988.
Language
•Plauger, P.J. and Jim Brodie. 1989.
Reference Series
•Plauger, P.J. and Jim Brodie. 1992.
Programmer's Reference
Neuron C Programmer’s Guide iii
, 2nd edition. Upper Saddle River, NJ: Prentice Hall, Inc.
Standard C: Programmer’s Quick
. Buffalo, NY: Microsoft Press.
ANSI and ISO Standard C
. Buffalo, NY: Microsoft Press.
The C Programming
Related Documentation
The following manuals are available from the Echelon Web site
www.echelon.com) and provide additional information that can help you develop
(
Neuron C applications for L
ONWORKS devices:
Introduction to the LONW
•
ORKS
Platform
(078-0391-01A). This manual
provides an introduction to the ISO/IEC 14908 (ANSI/CEA-709.1 and
EN14908) Control Network Protocol, and provides a high-level
introduction to L
ONWORKS networks and the tools and components that
are used for developing, installing, operating, and maintaining them.
I/O Model Reference for Smart Transceivers and Neuron Chips
•
(0780392-01A). This manual describes the I/O models that are available for
Echelon’s Smart Transceivers and Neuron Chips.
LonMaker User's Guide
•
use the LonMaker
control, maintain, and manage a L
•
LONM
®
ARK
Application Layer Interoperability Guidelines.
(078-0333-01A). This manual describes how to
®
Integration Tool to design, commission, monitor and
ONWORKS network.
This manual
describes design guidelines for developing applications for open
interoperable L
Web site,
Mini FX User’s Guide
•
ONWORKS devices, and is available from the LONMARK
www.lonmark.org.
(078-0398-01A). This manual describes how to use
the Mini FX Evaluation Kit. You can use the Mini FX to develop a
prototype or production control system that requires networking, or to
evaluate the development of applications for such control networks using
ONWORKS platform.
the L
Neuron C Reference Guide
•
(078-0140-01F). This manual provides
reference information for writing programs using the Neuron C Version
2.2 programming language.
Neuron Tools Errors Guide
•
(078-0402-01A). This manual documents and
explains the various warning and error messages that can occur for the
various Neuron C development tools.
NodeBuilder® FX User’s Guide
•
how to develop a L
ONWORKS device using the NodeBuilder tool.
All of the Echelon documentation is available in Adobe
(078-0405-01A). This manual describes
®
PDF files, you must have a current version of the Adobe Reader
download from Adobe at:
www.adobe.com/products/acrobat/readstep2.html.
Typographic Conventions for Syntax
Table 1 on page v lists the typographic conventions used in this manual for
displaying Neuron C syntax.
iv
PDF format. To view the
®
, which you can
Table 1. Typographic Conventions
Typeface or Symbol Used for Example
boldface type keywords
literal characters
italic type
[square brackets] optional fields [
| vertical bar a choice between two
Example: The syntax for declaring a network variable is:
network input | output [
abstract elements
elements
netvar modifier] [class] type [bind-info] identifier
• You type the keywords network, input, and output as shown
• You replace the abstract elements
identifier
and
identifier for the network variable
•The declaration must include either input or output, but not both
with the actual modifier, class, type, bind information, and
netvar modifier, class, type, bind-info
network
{
identifier
bind-info
input | output
]
,
•The elements
When a particular element or expression includes punctuation, such as quotation
marks, parentheses, and semicolons (but not including square brackets and
vertical bars), you must type that punctuation as shown.
Code examples appear in the monospace Courier font:
#include <mem.h>
unsigned array1[40], array2[40];
// See if array1 matches array2
if (memcmp(array1, array2, 40) != 0) {
// The contents of the two areas do not match
}
This chapter introduces the Neuron C Version 2.2
programming language. It describes the basic aspects of the
language and provides an overview to using the L
platform and the Neuron C programming language to
construct interoperable devices and systems. The chapter
also introduces key concepts of Neuron C such as eventdriven scheduling, network variables, configuration
properties, and functional blocks (which are
implementations of functional profiles).
A secondary purpose of this chapter is to introduce
fundamental material on Neuron C concerning Neuron C
types, storage classes, data objects, and how the Neuron C
language compares to the ANSI C language.
ONWORKS
Neuron C Programmer’s Guide 1
What Is Neuron C?
Neuron C Version 2 is a programming language based on ANSI C that is
designed for Neuron Chips and Smart Transceivers. It includes network
communication, I/O, and event-handling extensions to ANSI C, which make it a
powerful tool for the development of L
few of these new
1
features:
ONWORKS applications. Following are a
•A new network communication model, based on
network variables
like or disparate devices.
•A new network configuration model, based on functional blocks and
configuration properties
configuration tools.
•A new type model based on standard and user
the market for interoperable devices by simplifying integration of devices
from multiple manufacturers.
•An extensive built-in set of
capabilities of Neuron Chips and Smart Transceivers.
•Powerful
statements, provide easy handling of network, I/O, and timer events.
•A high-level programming model that supports application-specific
interrupt handlers and synchronization tools.
Neuron C provides a rich set of language extensions to ANSI C tailored to the
unique requirements of distributed control applications. Experienced C
programmers will find Neuron C a natural extension to the familiar ANSI C
paradigm. Neuron C offers built-in type checking and allows the programmer to
generate highly efficient code for distributed L
Neuron C omits ANSI C features that are not required by the standard for freestanding implementations. For example, certain standard C libraries are not
part of Neuron C. Other differences between Neuron C and ANSI C are
described in
event-driven programming
Differences between Neuron C and ANSI C
, that simplifies and promotes data sharing between
, that facilitates interoperable network
I/O models
that support the powerful I/O
extensions, based on new when
ONWORKS applications.
functional blocks
resource files
on page 13.
that expands
and
Comparing Neuron C Version 2 to Version 1
Neuron C version 2 includes major enhancements to the language that greatly
simplify the development of devices that use functional blocks and configuration
properties. Prior to version 2, developers had to manually construct selfdocumentation strings for each device, network variable, and configuration
property. This process could be both time-consuming and error-prone. With
Neuron C version 2, the Neuron C compiler can automatically create and manage
these strings.
If any of the following Neuron C keywords appear in an application, the Neuron
C compiler automatically generates and manages the self-documentation strings:
•fblock
1
"New" means relative to the ANSI Standard C language.
2 Overview
• fb_properties
• nv_properties
• device_properties
• cp
• cp_family
You can still manually create the self-documentation strings, if necessary, by
avoiding the use of any of these keywords and by declaring the selfdocumentation strings using the Neuron C version 1 syntax. Using this syntax
could be useful for migrating older applications (created with the NodeBuilder 1.5
or LonBuilder tools) to the NodeBuilder FX Development Tool. Applications that
do not use these keywords still get the benefit of access to resource definitions
contained within resource files.
Unique Aspects of Neuron C
Neuron C implements all of the basic ANSI C types, and type conversions as
necessary. In addition to the ANSI C data constructs, Neuron C provides some
unique data elements.
ONWORKS applications. Network variables are data constructs that have
L
language and system firmware support to provide something that looks like a
variable in a C program, but has additional properties for propagating across a
ONWORKS network to or from one or more other devices on that network. The
L
network variables make up part of the
Network variables
device interface
are fundamental to Neuron C and
for a LONWORKS device.
Configuration properties
the device interface. Configuration properties allow the device’s behavior to be
customized using a network tool such as the LonMaker tool or a customized plugin created for the device.
Neuron C also provides a way to organize the network variables and
configuration properties in the device into
provides a collection of network variables and configuration properties, that are
used together to perform one task. These network variables and configuration
properties are called the
Each network variable, configuration property, and functional block is defined by
a type definition contained in a
configuration properties are defined by
configuration property types
profiles
Network variables, configuration properties, and functional blocks in Neuron C
can use
promotes the interconnection of disparate devices on a L
configuration properties, the standard types are called standard configuration
property types (SCPTs; pronounced
standard types are called standard network variable types (SNVTs; pronounced
snivets
profiles. If you cannot find standard types or profiles that meet your
requirements, Neuron C also provides full support for user network variable
types (UNVTs; pronounced
pronounced
(which are also called
standardized, interoperable types
). For functional blocks, the standard types are called standard functional
u-keep-its
are Neuron C data constructs that are another part of
functional blocks
functional block members
resource file
. Network variables and
.
network variable types
(CPTs). Functional blocks are defined by
functional profile templates
. The use of standardized data types
skip-its
u-nivets
), and user functional profiles.
), user configuration property types (UCPTs;
). For network variables, the
, each of which
(NVTs) and
functional
).
ONWORKS network. For
Neuron C Programmer’s Guide 3
Neuron C is designed to execute in the environment provided by the Neuron
system firmware. This firmware provides an
part of the Neuron C language’s run-time environment.
event-driven scheduling system
as
Neuron C also provides a lower-level
language in addition to the network variable model, but the network variable
model has the advantage of being a standardized method of information
interchange, whereas the messaging service is not standardized (with the
exception of its usage by the L
of network variables, both standard types and user types, promotes
interoperability between multiple devices from multiple vendors. The lower-level
messaging service allows for proprietary solutions in addition to the file transfer
protocol.
Another Neuron C data object is the
manipulated like variables. When a timer expires, the system firmware
automatically manages the timer events and notifies the program of those events.
Neuron C provides many built-in
objects
Chip or Smart Transceiver I/O hardware. Each I/O model fits into the eventdriven programming model. A function-call interface is provided to interact with
each I/O object.
Some I/O models, all I/O pins, and a dedicated, high-resolution system timer, can
also be used to trigger asynchronous interrupts.
The rest of this chapter discusses these various aspects of Neuron C in more
detail, and the remaining chapters cover these aspects in greater detail,
accompanied by many examples.
. These I/O models are standardized I/O “device drivers” for the Neuron
ONWORKS file transfer protocol, LW-FTP). The use
messaging service
timer
. Timers can be declared and
I/O models
, which are instantiated as
integrated into the
I/O
Neuron C Integer Constants
Negative constants are treated as a unary minus operation on a positive
constant, for example, -128 is a signed long, not a signed short. Likewise, -32768
is an unsigned long, not a signed long. To construct a signed short value of -128,
you must use a cast:
((signed short)(-128))
To construct a signed long value of –32768, you must also use a cast:
((signed long)(-32768))
Decimal integer constants have the following default types:
0 .. 127 signed short
128 .. 32767 signed long
32768 .. 65535 unsigned long
The default type can be modified with the u, U, l, and L suffixes. For example:
0L signed long
127U unsigned short
127UL unsigned long
256U unsigned long
Hexadecimal constants have the following default types, which can also be
modified as described above with the u, U, l, and L suffixes:
4 Overview
0x0 .. 0x7F signed short
0x80 .. 0xFF unsigned short
0x100 .. 0x7FFF signed long
0x8000 .. 0xFFFF unsigned long
Octal constants have the following default types, which can also be modified as
described above with the u, U, l, and L suffixes:
0 .. 0177 signed short
0200 .. 0377 unsigned short
0400 .. 077777 signed long
0100000 .. 0177777 unsigned long
Binary constants have the following default types, which can also be modified as
described above with the u, U, l, and L suffixes:
0b0 .. 0b01111111 signed short
0b10000000 .. 0b11111111 unsigned short
0b0000000100000000 .. 0b0111111111111111 signed long
0b1000000000000000 .. 0b1111111111111111 unsigned long
Neuron C Variables
The following sections briefly discuss various aspects of variable declarations.
Data types affect what sort of data the variable represents. Storage classes affect
where the variable is stored, whether it can be modified (and if so, how often),
and whether there are any device interface aspects to modifying the data.
Neuron C Variable Types
Neuron C supports the following C variable types. The keywords shown in
square brackets are optional; if omitted, they are assumed by the Neuron C
language, per the rules of the ANSI C standard.
[signed] long [int] 16-bit quantity
unsigned long [int] 16-bit quantity
signed char 8-bit quantity
[unsigned] char 8-bit quantity
[signed] [short] [int] 8-bit quantity
unsigned [short] [int] 8-bit quantity
enum 8-bit quantity (int type)
Neuron C provides some predefined enum types. One example is shown below:
typedef enum {FALSE, TRUE} boolean;
Neuron C also provides predefined objects that, in many ways, provide the look
and feel of an ANSI C language variable. These objects include Neuron C timer
and I/O objects. See the
see the
timer objects.
Timers
chapter in the
I/O Model Reference
Neuron C Reference Guide
for more details on I/O objects, and
for more details on
The extended arithmetic library also defines float_type and s32_type for IEEE
754 and signed 32-bit integer data respectively. These types are discussed in
great detail in the
Neuron C Programmer’s Guide 5
Functions
chapter of the
Neuron C Reference Guide
.
Neuron C Storage Classes
If no class is specified and the declaration is at file scope, the data or function is
global.
a function or a task. Global data (including all data declared with the static
keyword) is present throughout the entire execution of the program, starting
from the point where the symbol was declared. Declarations using extern
references can be used to provide forward references to variables, and function
prototypes must be declared to provide forward references to functions.
Upon power-up or reset of a Neuron Chip or Smart Transceiver, the global data
in RAM is initialized to its initial-value expression, if present, otherwise to zero
(variables declared with the eeprom or config class, as well as configuration
properties declared with the config_prop or cp_family keywords, are only
initialized when the application image is first loaded).
Neuron C supports the following ANSI C storage classes and type qualifiers:
auto Declares a variable of local scope. Typically, this would be within a
const Declares a value that cannot be modified by the application program.
File scope
is that part of a Neuron C program that is not contained within
function body. This is the default storage class within a local scope
and the keyword is normally not specified. Variables of auto scope
that are not also static are not initialized upon entry to the local
scope. The value of the variable is not preserved once program
execution leaves the scope.
Affects self-documentation (SD) data generated by the Neuron C
compiler when used in conjunction with the declaration of CP families
or configuration network variables.
extern Declares a data item or function that is defined in another module, in
a library, or in the system image.
not
static Declares a data item or function which is
other modules at link time. Furthermore, if the data item is local to a
function or to a when task, the data value is to be preserved between
invocations, and is not made available to other functions at compile
time.
In addition to the ANSI C storage classes, Neuron C provides the following
classes and class modifiers:
config Can be combined only with an input network variable declaration. A
config network variable is used for application configuration. It is
equivalent to const eeprom. Such a network variable is initialized
only when the application image is first loaded. The config class is
obsolete and is included only for legacy applications. The Neuron C
compiler does not generate self-documentation data for config-class
network variables. New applications should use the configuration
network variable syntax described Chapter
Properties to Configure Device Behavior
network Begins a network variable declaration. See Chapter
Communicate Using Network Variables
system Used in Neuron C solely to access the Neuron firmware function
library. Do not use this keyword for data or function declarations.
to be made available to
4,
Using Configuration
, on page 83.
3,
How Devices
, on page 43, for more details.
6 Overview
uninit When combined with the eeprom keyword (see below), specifies that
the EEPROM variable is not initialized or altered on program load or
reload over the network.
The following Neuron C keywords allow you to direct portions of application code
and data to specific memory sections:
• eeprom
• far
• offchip (only for Neuron Chips and Smart Transceivers
with external memory)
• onchip
• ram (only for Neuron Chips and Smart Transceivers
with external memory)
These keywords are particularly useful on the Neuron 3150 Chip and 3150 Smart
Transceivers, because a majority of the address space for these parts is mapped
off chip. See
description of memory usage and the use of these keywords.
Using Neuron Chip Memory
on page 176 for a more detailed
Variable Initialization
Initialization of variables occurs at different times for different classes. The
must
const variables, except for network variables,
of const variables occurs when the application image is first loaded into the
Neuron Chip or Smart Transceiver. The const ram variables are placed in offchip RAM that must be non-volatile. Therefore, the eeprom and config variables
are also initialized at load time, except when the uninit class modifier is included
in these variable definitions.
Automatic variables cannot be declared const because Neuron C does not
implement initializers in declarations of automatic variables.
Global RAM variables are initialized at reset (that is, when the device is reset or
powered up). By default, all global RAM variables (including static variables) are
initialized to zero at this time. Initialization to zero costs no extra code space, as
it is a firmware feature.
Initialization of I/O objects, input network variables (except for eeprom, config,
config_prop, or const network variables), and timers also occurs at reset. Zero is
the default initial value for network variables and timers.
Local variables (except static ones) are not automatically initialized, nor are their
values preserved when the program execution leaves the local scope.
be initialized. Initialization
Neuron C Declarations
Both ANSI C and Neuron C support the declarations listed in Table 2.
variables on one or more additional devices. A device’s network variables define
its inputs and outputs from a network point of view and allow the sharing of data
in a distributed application. Whenever a program writes into one of its
network variables (with the exception of output network variables that are
is an object on one device that can be
connected
to network
output
8 Overview
declared with the polled modifier), the new value of the network variable is
propagated
connected to that output network variable. If the output network variable is not
currently a member of any network variable connection, no transaction and no
error occurs.
across the network to all devices with
input
network variables
Although the propagation of network variables occurs through L
messages, these messages are sent implicitly. The application program does not
require any explicit instructions for sending, receiving, managing, retrying,
authenticating, or acknowledging network variable updates. A Neuron C
application provides the most recent value by writing into an output network
variable, and it obtains the most recent data from the network by reading an
input network variable.
Example:
network input SNVT_temp nviTemperature;
network output SNVT_temp nvoTemperature;
void f(void)
{
nvoTemperature = 2 * nviTemperature;
}
Network variables greatly simplify the process of developing and installing
distributed systems because devices can be defined individually, then connected
and reconnected easily into many new L
variables are discussed in detail in Chapter
Network Variables
Network variables promote interoperability between devices by providing a welldefined interface that devices use to communicate. Interoperability simplifies
installation of devices into different types of networks by keeping the network
configuration independent of the device’s application. A device can be installed in
a network and logically connected to other devices in the network as long as the
data types (for example, SNVT_switch or SNVT_temp_p) match. To further
promote interoperability, the L
profiles that define standard functional interfaces for devices, and standard
network variable types (SNVTs) that define standard data encoding, scaling, and
units, such as degrees C, volts, or meters. There are standard functional profiles
for a variety of functions and industries. There are SNVT definitions for
essentially every physical quantity, and other more abstract definitions tailored
for certain industries and common applications.
, on page 43, and also in the
ONWORKS platform provides standard functional
ONWORKS applications. Network
3,
How Devices Communicate Using
Neuron C Reference Guide
ONWORKS
.
You can also create your own user functional profiles and user network variable
types (UNVTs). You can define resource files for your custom types and profiles
to enable your devices to be used with devices from other manufacturers. The
NodeBuilder Resource Editor included with the NodeBuilder tool provides a
simple interface for viewing existing resources and defining your own resources.
Configuration Properties
A configuration property is a data item that, like a network variable, is part of
the device interface for a device. A configuration property can be modified by a
network tool. Configuration properties facilitate interoperable installation and
configuration tools by providing a standardized network interface for device
Neuron C Programmer’s Guide 9
configuration data. Like network variables, configuration properties also provide
a well-defined interface. Each configuration property type is defined in a
resource file that specifies the data encoding, scaling, units, default value, invalid
value, range, and behavior for configuration properties based on the type. A rich
variety of standard configuration property types (SCPTs) are available. You can
also create your own user configuration property types (UCPTs) that are defined
in resource files that you create with the NodeBuilder Resource Editor.
Functional Blocks and Functional Profiles
The
device interface
network variables, and configuration properties. A
of network variables and configuration properties that are used together to
perform one task. These network variables and configuration properties are
called the
functional block members
for a LONWORKS device consists of its functional blocks,
functional block
.
is a collection
Functional blocks are defined by
to describe common units of functional behavior. Each functional profile defines
mandatory and optional network variables and mandatory and optional
configuration properties. Each functional block implements an instance of a
functional profile. A functional block must implement all of the mandatory
network variables and configuration properties that are defined by the functional
profile, and can also implement any of the optional network variables and
configuration properties that are defined by the functional profile. In addition, a
functional block can implement network variables and configuration properties
that are not defined by the functional profile – these are called
specific
Functional profiles are defined in
profiles or you can define your own functional profiles in your own resource files
by using the NodeBuilder Resource Editor. A functional profile defined in a
resource file is also called a
L
L
requirements as specified by the
Guidelines
network variables and configuration properties.
ONMARK International provides a procedure for developers to certify devices.
ONMARK interoperable devices conform to all LonTalk
, and conform to all aspects of application design, as described in the
Contact L
becoming a member and certifying your devices.
You can automatically embed data within your device that identifies its device
interface to network tools that are used to install the device. This data is called
self-identification
compiler generates this data based on the functional blocks, network variables,
and configuration properties that you declare, as well as the resource files that
you provide. You can add your own documentation to the SD data to further
document your device and its interface.
ONMARK International at www.lonmark.org for more details about
(SI) data and
functional profiles
resource files
functional profile template
. A functional profile is used
. You can use standard functional
(FPT).
®
protocol layer 1 – 6
LonMark Layer 1 – 6 Interoperability
.
self-documentation
(SD) data. The Neuron C
implementation-
You can include network variable names in the SD data using the #pragma
enable_sd_nv_names directive. You can also include a rate estimate in tenths-ofmessages/second and a maximum rate estimate in tenths-of-messages/second in
the SD data for each network variable. The rate estimate and maximum rate
estimate values are provided through the bind_info feature. (See the discussion
10 Overview
of this feature in Chapter
Variables
An application image for a device created by the Neuron C compiler contains SD
information unless the #pragma disable_snvt_si directive is used. (See the
Compiler Directives
information.)
, on page 43, and also in the
3,
How Devices Communicate Using Network
chapter of the
Neuron C Reference Guide
Neuron C Reference Guide
.)
for more
Data-Driven Compared with CommandDriven Protocols
Network variables are used to communicate data and state information between
devices. This data-driven model provides a different communication model than
in command-based systems. In command-based messaging systems, designers
are faced with having a large number of commands, specific to each application,
that must be managed, updated, and maintained. Each device has to have
knowledge of every command. This leads to ever-growing command tables and
application code.
With network variables, the command or action portion of a message is not in the
message. Instead, with network variables, this information is in the application
program, and each application program only needs have the knowledge required
to perform its function. A network integrator can add new types of devices at any
time, and connect them to existing devices in the network to perform new
applications not envisioned by the original designers of the devices.
Event-Driven Scheduling or Polled Scheduling
Although the Neuron C language is principally designed to make event-driven
scheduling natural and easy, Neuron C also allows you to construct polled
applications that implement a centralized control application. Chapter
Devices Communicate Using Network Variables
information on polling.
, on page 43, provides further
Low-Level Messaging
In addition to the functional block and network variable communication model,
Neuron C also supports application messages. You can use application messages
– in place of or in conjunction with the network variables approach – to
implement proprietary interfaces to your devices. They are also used for the
ONWORKS file transfer protocol. Application messages are described in Chapter
L
6,
How Devices Communicate Using Application Messages
, on page 117.
I/O Devices
A Neuron Chip or Smart Transceiver can be connected to one or more physical
I/O devices. Examples of simple I/O devices include temperature and position
sensors, valves, switches, and LED displays. Neuron Chips and Smart
Transceivers can also be connected to other microprocessors. The Neuron
firmware implements numerous
devices for a Neuron C application. I/O models are discussed in detail in Chapter
2,
Focusing on a Single Device
I/O models
, on page 15, and in the
that manage the interface to these
I/O Model Reference
3,
How
.
Neuron C Programmer’s Guide 11
Neuron-Hosted and Host-Based Compilation
Compilation for Neuron-hosted devices, that is, devices based on a Neuron Chip
or Smart Transceiver as the main processor, use Neuron C to define all aspects of
the device’s application:
•The application’s interoperable interface, including its set of network
variables, configuration properties, and functional blocks, and the selfidentification and self-documentation data
• Device configuration information, such as buffer configuration
• Application code including, when tasks, interrupt tasks, I/O device
declarations, and functions
Compilation for host-based devices, that is, devices that implement the
application on a different processor (the
Neuron C language to model the device’s interoperable interface. For these
devices, the Neuron C source code acts as a model for the finished application,
and the primary source file is called the
devices uses Neuron C to define only the following aspect of the device’s
application:
•The application’s interoperable interface, including its set of network
variables, configuration properties, and functional blocks, and the selfidentification and self-documentation data
The ShortStack Developer’s Kit, FTXL Developer’s Kit, and the
SmartServer all use model files. See the related product documentation for
information about compiling a model file, and about implementing the device’s
application (including the device configuration information and application code).
host processor
model file
), often use a subset of the
. Compilation for host-based
i
.LON
Syntactically, a Neuron C application and a model file differ in the following
ways:
•Declaration of the interoperable interface is largely identical, however, a
few exceptions exist which are identified throughout this book, as
necessary.
•Device configuration is typically adjusted using a product-specific tool,
such as the LonTalk Interface Developer utility, and is not specified in a
model file. When encountered within a model file, device configuration
constructs can trigger a compiler error or warning.
•Application code, including I/O device declarations, application timer
declarations and any form of executable code, is ignored in a model file.
Such code results in a warning for model file compilation, and the code
has no effect.
You can use conditional compilation to prepare the same source code for use as
Neuron C application and a model file. The _MODEL_FILE preprocessor symbol
is automatically predefined for model file compilation, and is not predefined for
application compilation. See the
about predefined preprocessor symbols.
Neuron C Reference Guide
for more information
12 Overview
Differences between Neuron C and ANSI C
Neuron C adheres closely to the ANSI C language standard; however, Neuron C
is not a "conforming implementation" of Standard C, as defined by the American
National Standards Institute committee X3-J11.
The following list outlines the major differences between Neuron C and ANSI C:
•Neuron C does not support floating-point computation with C syntax or
operators. However, a floating-point library is provided to allow use of
floating-point data that conforms to the IEEE 754 standard.
•ANSI C defines a short int as 16 bits or more and a long int as 32 bits or
more. Neuron C defines a short int as 8 bits and a long int as 16 bits. In
Neuron C, int defaults to a short int. A 32-bit signed integer library is
available to allow use of 32-bit quantities.
•Neuron C does not support the register or volatile classes. These storage
classes can be specified but are ignored.
•Neuron C does not implement initializers in declarations of automatic
variables.
•Neuron C does not support structures or unions as procedure parameters
or as function return values.
•Neuron C does not support declaration of bitfields as members of unions.
However, an equivalent declaration can be accomplished by defining a
structure as a member of the union, where the structure contains the
bitfields.
• Pointers to timers, to message tags, or to I/O objects are not supported.
• Pointers to network variables, configuration properties, and EEPROM
variables are treated as pointers to constants (that is, the contents of the
variable referenced by the pointer can be read, but not modified). Under
special circumstances, and with certain restrictions, the pointers can be
used to modify the memory. See the discussion of the eeprom_memcpy( )
8,
function in Chapter
Functions
discussion of the #pragma relaxed_casting_on compiler directive in the
chapter of the
Compiler Directives
•Macro arguments are not rescanned until after the macro is expanded,
thus the macro operators # and ## might not yield results as defined in
the ANSI C standard when they occur in nested macro expansions.
•Names of network variables and message tags are limited to 16
characters. Names of functional blocks are limited to 16 characters
unless they are declared using the external_name feature, in which case
the external name is limited to 16 characters, and the internal name of
the functional block is limited to 64 characters.
Memory Management
Neuron C Reference Guide
chapter of the
Neuron C Reference Guide
, on page 173, and also in the
. Also refer to the
.
•A few ANSI C library functions are included in Neuron C, such as
memcpy( ) and memset( ). A string and byte operation library is provided
to allow use of a subset of the ANSI C functions defined in the <string.h>
Neuron C Programmer’s Guide 13
include file. Other ANSI C library functions, such as file I/O and storage
allocation functions, are not included in Neuron C. Consult the
Reference Guide
•The Neuron C implementation includes three ANSI include files:
<stddef.h>, <stdlib.h>, and <limits.h>.
•Neuron C requires use of the function prototype feature whenever a call
to the function precedes the function definition (see Chapter
on a Single Device
•Neuron C does not support the use of the ellipsis (...) in function
prototypes or definitions.
•Neuron C contains additional reserved words and syntax not found in
ANSI C. See the
the list of reserved words.
•Neuron C supports binary constants in addition to octal and hexadecimal.
Binary constants are specified as 0b
0b1101 equals decimal 13.
•Neuron C supports the // comment style from C++, in addition to the
traditional /* */ C coment style. In the // style, two slashes (//) begin a
comment. The comment is terminated by the end of the line, without
further punctuation.
C code /* An ANSI C and NEURON C comment */
C code // A line-style NEURON C comment
for a complete and detailed list.
, on page 15).
Neuron C Reference Guide
for the syntax summary and
<binary_number>
. For example,
Neuron C
2,
Focusing
•The main( ) construct is not used. Instead, a Neuron C program’s
executable objects consist of when statements in addition to functions. A
thread of execution always begins with a when statement, as described in
2,
Chapter
•Neuron C does not support multiple source files in separate compilation
units (however, the #include directive is supported).
•The ANSI C preprocessor directives #if, #elif, and #line are not supported.
However, #ifdef, #ifndef, #else, and #endif are supported.
•The Neuron C implementation of the #error directive requires a double-
quoted string for the error message; the ANSI C directive does not.
See Appendix
237 for a description of how the Neuron C language conforms to “implementationspecific” aspects of the ISO and ANSI C language definitions.
Focusing on a Single Device
D,
Neuron C Language Implementation Characteristics
, on page 15.
, on page
14 Overview
2
Focusing on a Single Device
This chapter describes the Neuron C event scheduler and I/O objects.
The concepts of
introduced.
I/O and timer objects, and I/O functions.
Objects that can be defined for each Neuron C application include
timers
variables
in Chapter 4;
application messages
and
, described in Chapter 3;
predefined events
Code examples in this chapter illustrate the use of events,
input/output (I/O) objects
functional blocks
, described in Chapter 6.
and
user-defined events
, described here;
configuration properties
, described in Chapter 5; and
network
, described
are
Neuron C Programmer’s Guide 15
What Happens on a Single Device?
In this chapter, you begin to learn about programming a Neuron Chip or Smart
Transceiver by focusing first on a single device. Each Neuron Chip and each
Smart Transceiver has standard firmware, called the
hardware support that implement a scheduler, timers, and I/O device drivers and
interfaces. Series 5000 chips also provide hardware support for interrupts; see
Interrupts
The Neuron C language includes predefined objects that provide access to these
firmware features. These objects are described briefly here, and in more detail
later in this chapter:
on page 153 for more information.
Neuron firmware
, and
•The Neuron firmware's
application program. This chapter explains how to use the Neuron C
language to define events and tasks, how the scheduler evaluates
nonpriority events, and how you can define priority events.
•The Neuron C language offers two types of
second timers. These timers can be used to affect the scheduling of tasks,
as described in
•A number of
ANSI C. These I/O objects, as well as related I/O functions and events,
are described in
The Scheduler
The scheduling of application program tasks is event driven: when a given
condition becomes TRUE, a body of code (called a
condition is executed. The scheduler allows you to define tasks that run as the
result of certain events, such as a change in the state of an input pin, receiving a
new value for a network variable, or the expiration of a timer. You can also
specify certain tasks as priority
Priority When Clauses
(see
specify interrupt tasks that are serviced independently of the scheduler; see
Interrupts
on page 153 for more information.
event scheduler
Timers
I/O objects
on page 25.
can be declared using Neuron C extensions to
Input/Output
on page 23). Series 5000 chips also allow you to
on page 27.
tasks, so that they receive preferential service
handles task scheduling for the
timer
objects: millisecond and
task
) associated with that
When Clauses
Events are defined through when clauses. A when clause contains an expression
task
that, if evaluated as TRUE, causes the body of code (the
expression to be executed to completion. Multiple when clauses can be associated
with a single task. A simple when clause and its associated task are shown
below. The when clause or clauses and the associated task are frequently
referred to as one entity known as a
when (timer_expires(led timer))
when task
or a
when statement
{
// Turn off the LED
io_out(io_led, OFF);
}
16 Focusing on a Single Device
) following the
.
when clause
task
In this example above, when the led_timer application timer (definition not
shown in this example) expires, the body of code (the task) that follows the when
clause is executed to turn off the specified I/O object, io_led (also defined
elsewhere in the program). After this task has been executed, the timer_expires
event is automatically cleared. Its task is then ignored until the LED timer
expires again and the when clause again evaluates to TRUE.
The following examples demonstrate various ways of using tasks and events.
7,
More information about tasks and events can be found in Chapter
Features
The when clauses cannot be nested. For example, the following nested when
clause is not valid:
, on page 145, and Figure 14 on page 147.
when (reset)
when (io_changes(io_switch))
when (!timer_expires)
when (flush_completes && (y == 5))
when (x == 3)
{
// Turn on the LED and start the timer
. . .
}
when (io_changes(io_switch))
{
when (x == 3) { // Can't nest!
...
}
}
Additional
An equivalent result may be achieved by testing the event with an if statement:
when (io_changes(io_switch))
{
if (x == 3) {
...
}
}
When Statement
The syntax for a when statement (the when clause or clauses plus the associated
task) is:
when-clause
[when-clause ... ]
task
The syntax for
[priority] [preempt_safe] when (
priority Forces evaluation of the following when clause each time the
preempt_safe Allows the scheduler to execute the associated when task
when-clause
scheduler runs. See
even if the application is in preemption mode. See the discussions on
preemption mode in Chapter
Application Messages
is:
event
)
Priority When Clauses
6,
How Devices Communicate Using
, on page 117.
on page 23.
Neuron C Programmer’s Guide 17
event
This expression is either a predefined event (see the following section)
or any valid Neuron C expression (which can contain a predefined
event). Predefined events as well as expressions are enclosed in
parentheses. One or more when clauses can be associated with the
same task.
task
A Neuron C compound statement, consisting of a series of Neuron C
declarations and statements, enclosed in braces, which are identical
to those found in a Neuron C function definition. The task is
identical to the body of a void function (that is, it cannot return a
value). A return statement can be used to terminate execution of the
task but is not required.
Types of Events Used in When Clauses
The events defined in a when clause fall into two general categories: predefined
events and user-defined events.
compiler. Examples of predefined events include input pin state changes,
network variable changes, timer expiration, and message reception.
defined events
to a Boolean value.
The distinction between user-defined events and predefined events is not critical.
Use predefined events whenever possible, because they require less code space.
There is one exception to the statement that a when clause can be any valid C
expression. The offline, online, and wink predefined events must appear by
themselves if used. All other predefined events may be combined into any
arbitrary expressions. This restriction only applies to when clauses.
can be any valid Neuron C expression that evaluates or converts
Predefined events
use keywords built into the
User-
Examples:
when (msg_arrives) // O.K.
when (msg_arrives && flag == TRUE) // O.K.
when (online) // O.K.
when (online && flag == TRUE) // Not permitted.
Predefined Events
The timer_expires event shown earlier is one type of predefined event. Table 4
lists other predefined events that are represented by unique keywords.
Predefined Event Where Described in This Manual
flush_completes Chapter 7
io_changes this chapter
io_in_ready this chapter
io_out_ready this chapter
io_update_occurs this chapter
Table 4. Predefined Events
18 Focusing on a Single Device
Predefined Event Where Described in This Manual
msg_arrives Chapter 6
msg_completes Chapter 6
msg_fails Chapter 6
msg_succeeds Chapter 6
nv_update_occurs Chapter 3
nv_update_completes Chapter 3
nv_update_fails Chapter 3
nv_update_succeeds Chapter 3
offline Chapter 7
online Chapter 7
reset this chapter
resp_arrives Chapter 6
timer_expires this chapter
wink Chapter 7
A modifier that narrows the scope of the event may follow some predefined
events, such as the I/O events and network variable events. If the modifier is
optional and not supplied, any event of that type qualifies.
Predefined events can also be used as any sub-expression, including within the
control expression of if, while, and for statements. This method is termed
event processing
mtimer t;
when (event)
{
. . .
if (timer_expires(t)) {
io_out(io_led, OFF);
}
. . .
}
. An example of direct event processing is:
direct
Any built-in event keyword or keyword expression (such as timer_expires(t)) is
treated the same as any other sub-expression and any combination allowed by
standard C expression syntax is allowed when programming in Neuron C.
The special case of the io_changes event expression
The to and by qualifier keywords are treated as general expression operators for
purposes of precedence (although they are only permitted in combination with
Neuron C Programmer’s Guide 19
must be treated carefully
.
io_changes). These operators are of equal precedence with each other, but they
are mutually exclusive. They are of higher precedence than relational operators
(that is, comparisons), but lower in precedence than shift and arithmetic
operators.
Following are examples of how the io_changes event expression is parsed:
device
device
) by a + b
) by (a + b)
io_changes (
:
as
io_changes (
and
io_changes (
:
as
(io_changes (
As with any other C operators, the implied precedence can be explicitly changed
by parenthesization. Parentheses should
code if there is any doubt. Use of extra parentheses has no negative effect upon
the compilation or the code generated.
The Neuron C compiler detects the use of predefined event keywords in when
clauses and treats them specially for code optimization purposes. However, when
event keywords are used as sub-expressions within when clauses, event table
optimizations cannot be used. In the examples below, the first case uses the
event table optimization, the second and third do not:
when (timer_expires) { }
when (! timer_expires) { }
if (timer_expires)
Although the io_changes expression (by and to varieties) does not
constant value, only
the when clause event table.
device
) by a < b
device
) by a) < b
constant-valued
always
io_changes expressions are optimized into
be used to improve clarity of the
require
a
Event Processing
Events related to network activity are processed using two separate queues. One
queue serves the following events related to incoming network messages:
nv_update_occurs
msg_arrives
online
offline
wink
The other queue serves the remaining network events pertaining to completion
events and responses:
nv_update_completes
nv_update_succeeds
nv_update_fails
msg_completes
20 Focusing on a Single Device
msg_succeeds
msg_fails
resp_arrives
Most network events, except resp_arrives, are enqueued only if the Neuron C
compiler has determined that the application checks for the event. The online,
offline, and wink events are always enqueued but are discarded by the scheduler
if no corresponding when clause is found.
When it reaches the head of the queue, an event remains there until processed by
the application. Therefore, any network event that is checked for by an
application must be checked for frequently, or the event remains at the head of
the queue, effectively blocking that queue. A blocked queue prevents the
application from continuing normal processing of events and can cause the device
to fail to respond to any subsequent application or network management
messages.
This is a particularly critical consideration for nv_update_occurs and msg_arrives
events, which can arrive unsolicited at any time; in comparison, completion
events and responses arrive only as the result of application-initiated outgoing
network activity. The Neuron C compiler determines that an event is handled by
the application by virtue of its presence in the program, even if it is never
checked for in a when clause, or is only checked for in special circumstances.
Reset Event
The reset event is TRUE the first time this event is evaluated after the Neuron
Chip or Smart Transceiver is reset for any reason. Note that I/O object and
global variable initializations are performed before processing any events. The
reset event task
Smart Transceiver.
The reset event task executes only if the device is in the configured state (that is,
if the device is not applicationless, hard-offline, or unconfigured). Also, the reset
event task runs when the device is unconfigured if the directive #pragma
run_unconfigured is specified in the application program. The task runs
regardless of whether the device is soft-offline or not. The soft-offline state is not
reset-retained, so the only case where this is meaningful is when the device
transitions from unconfigured or hard-offline to configured state after a reset, as
would typically happen during initial commissioning. In this case, the device
executes the reset task followed by the offline task.
A reset occurs as a natural part of the process of commissioning a L
device, and the reset process includes the execution of the reset event task. The
device undergoes a state transition to complete the commissioning process, and
that state transition can only be completed after the reset event task has been
executed. Consequently, you should keep the reset event task short so that the
device can be commissioned at maximum speed. You must keep the total reset
event task processing time under 18 seconds to prevent commissioning failures.
Reset event task processing time includes Neuron firmware initialization time as
described in the Smart Transceivers databooks.
is the first task to be executed after reset of the Neuron Chip or
ONWORKS
Neuron C Programmer’s Guide 21
User-Defined Events
A user-defined event can contain assignments and function calls. Such events
using complex expressions can affect the response time for all events within a
program, so you must minimize calls to complex functions within user-defined
events. Assignments within user-defined events can only be done to global
variables.
Furthermore, the evaluation of an event keyword or an event expression, such as
timer_expires(t), clears any pending event, regardless of whether the entire
expression is TRUE or FALSE, as below:
when ((timer_expires(t)) && (flag = = TRUE))
As with ANSI C compilers, the Neuron C compiler evaluates logical expressions
only as much as needed. For example, in an if (a && b) expression, the b term is
only evaluated if a is TRUE, and in an if (a || b) expression, the b term is only
executed if a is FALSE. This is called
the ANSI C language definition.
When combining user-defined expressions with a predefined event using the
logical operators discussed in the paragraph above, you must make sure that this
does not prevent the predefined events from being evaluated as needed, in order
to avoid blockage of the event queue as discussed earlier in this chapter.
For example, the following user-defined event expression is okay:
when ((timer_expires(t)) && (flag = = TRUE))
short-circuit evaluation
, and is specified by
But, if the expression above is reversed, as shown below, it is likely to cause a
blockage of the event queue if the flag variable is true for any significant time,
because the short-circuit nature of the logical-and operator can prevent the timer
expiration event from being checked at all. Thus, the reversed expression shown
below must be avoided:
when ((flag = = TRUE) && (timer_expires(t)))
Scheduling of When Clauses
The scheduler evaluates when clauses in round-robin fashion: Each when clause
is evaluated by the scheduler and, if TRUE, the task associated with it is
executed. If the when clause is FALSE, the scheduler moves on to examine the
following when clause. After the last when clause, the scheduler returns to the
top and moves through the group of when clauses again.
Example: A group of when clauses might look like the following:
when (nv_update_occurs) // Event A
// {task to execute}
when (nv_update_fails) // Event B
// {task to execute}
when (io_changes) // Event C
// {task to execute}
when (timer_expires) // Event D
// {task to execute}
22 Focusing on a Single Device
Letter names shown above are used for the clauses in
narration of events. This shows how the order of execution of tasks differs from
the order the when clauses appear in a program.
At the start of this example, no event has occurred, thus no when clause event
expression is TRUE.
1 The scheduler begins with A. Since A is FALSE, its task is not executed.
2 Event C occurs and the expression C becomes TRUE.
3 The scheduler moves to B. Since B is FALSE, its task is not executed.
4 The scheduler moves to C. Since C is TRUE (item 2, above), its task is
executed.
5 A becomes TRUE.
6 The scheduler moves to D. Since D is FALSE, its task is ignored.
7 The scheduler moves back to A. Since A is TRUE (item 5, above), its task
is executed.
Figure 1 and the following
Figure 1. Example Scheduler Timeline
Priority When Clauses
The priority keyword can be used to designate when clauses that should be
evaluated more often than nonpriority when clauses. Priority
every
evaluated in the order specified
when clause evaluates to TRUE, the corresponding task is executed and the
scheduler starts over at the top of the priority
If none of the priority when clauses evaluates to TRUE, then a nonpriority when
clause is evaluated, selected in the round-robin fashion described earlier. If the
selected nonpriority when clause evaluates to TRUE, its task is executed. The
scheduler then resumes with the first priority when
Neuron C Programmer’s Guide 23
time the scheduler runs. If any priority
when clauses.
clause. If the nonpriority
when clauses are
when clause selected evaluates to FALSE, its task is ignored and the scheduler
resumes with the first priority when
The scheduling algorithm described above can be modified through use of the
scheduler_reset pragma, discussed in Chapter 7,
145.
Important: Excessive use of priority when clauses might starve execution of
nonpriority when clauses. If a priority when clause is true the majority of the
time, it monopolizes processor time. Priority when clauses should be designed to
be true only rarely, or the remaining tasks must be tolerant of not being executed
frequently and responsively.
Interrupts
Neuron C supports application-specific asynchronous interrupts from various
interrupt sources, and provides a semaphore for synchronization in a
multiprocessing environment.
Each interrupt statement consists of an interrupt clause, followed by an
interrupt task. Unlike when statements, which can include more than one when
clause, interrupt statements support only a single interrupt clause.
The interrupt clause defines the interrupt source and the conditions that trigger
the interrupt. The interrupt task contains code that runs as a result of the
interrupt.
clause. See Figure 14 on page 147.
Additional Features
, on page
Example:
interrupt(IO_3, clockedge(-)) {
...
}
Interrupt clauses support interrupt requests from signal conditions on I/O pins,
from timer or counter I/O objects, or from the high-resolution system timer.
A simple __lock{ } construct implements synchronization through a hardware
semaphore.
Interrupts
See
on page 153 for more information.
Function Prototypes
Neuron C requires the use of function prototypes if a function is to be called
before it is defined. Examples of valid prototypes include the following:
void f(void);
int g(int a, int b);
The following are not considered prototypes because they do not have argument
lists. They are merely forward declarations:
void f();
g(); // defaults to 'int' return value
If you define a function before you call it, Neuron C automatically creates an
internal prototype for you. Only one prototype is created for a given function.
The following examples are technically not prototypes, but Neuron C creates
function prototypes for them:
24 Focusing on a Single Device
Although Neuron C can create prototypes, it does
Miranda prototype rule. According to the Miranda prototype rule, if a function
call does not already have a prototype, a prototype is automatically created for it.
In Neuron C, a function prototype is automatically created only when the
function is defined.
Timers
Two types of software timer objects are available to a Neuron C application:
millisecond timers and second timers. The millisecond timers provide a timer
duration of 1 to 64,000 milliseconds (or .001 to 64 seconds). The second timers
provide a timer duration of 1 to 65,535 seconds. For more accurate timing of
durations of 64 seconds or less, use the millisecond timer. These timers are
separate from the two hardware timer/counters in the Neuron core (see also
Input Clock Frequency and Timer Accuracy
void f()
{ /* body */ }
g (a,b)
int a;
int b;
{ /* body */ }
not
employ the ANSI C
on page 36).
For Series 5000 chips, a high-resolution hardware timer is also available. You
can program an interrupt handler to asynchronously handle interrupts that occur
based on this hardware timer; see
Declaring Timers
A maximum of 15 timer objects (total of both types) can be defined within a single
program. A timer object is declared using one of the following:
mtimer [repeating]
stimer [repeating]
mtimer Indicates a millisecond timer.
stimer Indicates a second timer.
repeating An option for the timer to restart itself automatically upon expiration.
With this option, accurate timing intervals can be maintained even if
the application cannot respond immediately to an expiration event.
timer-name
this name starts the timer for the specified length of time (the
specified time is in seconds for an stimer and milliseconds for an
mtimer). A timer that is running or has expired can be started over
by assigning a new value to this name. The timer object can be
evaluated while the timer is running, and it indicates the time
remaining. Setting the timer to 0 turns the timer off. No timer
expiration event occurs for a timer that has been turned off (see the
description of the timer_expires event described in the
Reference Guide
Interrupts
timer-name
timer-name
A user-supplied name for the timer. Assigning a value to
[=
initial-value
[=
initial-value
on page 153 for more information.
];
];
Neuron C
).
Neuron C Programmer’s Guide 25
initial-value
An optional initial value to be loaded into the timer on
power-up or reset. Zero is loaded by the Neuron firmware (in other
words, the timer is turned off) if no explicit initial-value is supplied.
Examples
An example of declaring a timer object and assigning a value to it is shown below:
// start timer with value of 5 sec
stimer led_timer = 5;
An example of turning a timer off is shown below:
stimer led_timer;
when (some-event)
{
led_timer = 0;
}
An example of evaluating the value of a running timer is shown below:
Note: When setting and examining timers in the NodeBuilder debugger, certain
inaccuracies could occur. When a timer is set during program execution and is
examined while the program is halted (includes single stepping and breakpoints),
the timer value can be as much as 200 milliseconds larger than the actual time
until expiration. No such inaccuracy exists on a timer that is allowed to run
without a debugger halt.
The timer_expires Event
The timer_expires event becomes TRUE when a timer expires. The syntax of this
event is the following:
timer_expires [(
timer-name
If
timer-name
unqualified event
An
that limits the objects to which the event applies.
A timer event is unique because it can be cleared only by checking for specific
(qualified) timer expiration events. Other events can be cleared by checking for
either the qualified or unqualified events. For example, the following when
clause checks for the expiration of the led_timer, so the timer_expires event for
that timer is cleared to FALSE.
Examples:
stimer led_timer;
when (timer_expires(led_timer))
{
io_out(io_led, OFF); // Turn off the LED
Specifies a specific timer to check.
timer-name
is not included, the event is an unqualified timer_expires event.
expression is one that omits the optional qualifier syntax
)]
26 Focusing on a Single Device
}
If your program has multiple timers, you must include a specific check for each
timer so that the expiration event is cleared, as shown below:
mtimer x;
mtimer y;
mtimer z;
when (timer_expires(x))
{
// task
}
when (timer_expires(y))
{
// task
}
when (timer_expires(z))
{
// task
}
An alternate style of checking for specific timers is shown below. This example
also demonstrates that an event expression is not restricted to use only in a when
clause.
when (timer_expires)
{
if (timer_expires(x))
...
else if (timer_expires(y))
...
else if (timer_expires(z))
...
}
Note: Be sure to check for specific timer events while using the unqualified
timer_expires event. Unlike all other predefined events, which are TRUE only
once per pending event, the unqualified
long as
Which style you choose to use for checking timer expiration depends on the
circumstances in your application. Use the first style of checking for specific
timers if you’re concerned about code space. Use the second style if you’re
concerned about speed of execution, performance, or response time.
For an example of a complete program that declares a timer and uses the
timer_expires event, see
any
Input/Output
Each Neuron Chip and each Smart Transceiver has a variety of built-in electrical
interface options for performing input and output (I/O) functions. Before
performing I/O, you must first declare the I/O objects that monitor and control
the 11 or 12 Neuron Chip or Smart Transceiver I/O pins, named IO_0, IO_1, ...,
IO_11.
To perform I/O, you normally use the built-in I/O functions: io_in( ), io_out( ),
io_set_direction( ), io_select( ), io_change_init( ), and io_set_clock( ). The
io_out_request( ) function is used to perform I/O with the parallel I/O object. I/O
timer has expired.
Example 1: Thermostat Interface
timer_expires event remains TRUE as
on page 31.
Neuron C Programmer’s Guide 27
objects can also be linked to Neuron C events, because changes in I/O often affect
task scheduling.
The Neuron C declaration syntax for I/O objects is described in detail in the
Model Reference for Smart Transceivers and Neuron Chips
I/O Object Types
Many I/O models are available for Neuron Chips and Smart Transceivers.
Certain I/O models are available only for specific chip types, but most are
available to all Neuron Chips and Smart Transceivers. A Neuron C application
instantiates an I/O model as an I/O object.
The I/O models are grouped into the following categories:
Direct I/O Models
•
Neuron Chip or Smart Transceiver hardware's timer/counters are used in
conjunction with these I/O models. These models can be used in multiple,
overlapping combinations within the same Neuron Chip or Smart
Transceiver. Direct I/O models include the following types:
Input Model Types Output Model Types
bit bit
byte byte
leveldetect nibble
nibble touch
touch
Timer/Counter I/O Models
•
or Smart Transceiver. Each Neuron Chip and each Smart Transceiver
has two timer/counter circuits: One whose input can be multiplexed, and
one with a dedicated input. Timer/counter I/O models include the
following types:
Input Model Types Output Model Types
dualslope edgedivide
edgelog frequency
infrared infrared_pattern
ontime oneshot
period pulsecount
pulsecount pulsewidth
quadrature stretchedtriac
totalcount triac
triggeredcount
I/O
.
are based on a logic level at the I/O pins; none of the
use a timer/counter circuit in the Neuron Chip
Serial I/O Models
•
set of pins. The neurowire, i2c, magcard, magcard_bitstream, magtrack1,
and serial I/O models are mutually exclusive within a single Neuron Chip
or Smart Transceiver. Both the input and output versions of a serial I/O
model can coexist within a single Neuron Chip or Smart Transceiver.
Serial I/O models include the following types:
are used for transferring data serially over a pin or a
Serial Input Model Types Serial Output Model Types
bitshift bitshift
magcard serial
magcard_bitstream
28 Focusing on a Single Device
magtrack1
serial
wiegand
Serial Input/Output Model Types
i2c
neurowire
sci
spi
Parallel I/O Models
•
within this group use all of the Neuron Chip or Smart Transceiver I/O
pins. The parallel I/O models include the following types:
Parallel Input/Output Model Types
muxbus
parallel
are used for high-speed bidirectional I/O. I/O models
Declaring I/O Objects in Neuron C
Declaring an I/O object in a Neuron C application performs both of the following
tasks:
•Informs the compiler what type of I/O operation is performed, and on
which pin or pins. The compiler creates instructions that configure the
hardware within the Neuron core as a result of this declaration. The
firmware configures the hardware whenever the device or application is
reset.
•Associates the name of the I/O object with the hardware.
The general syntax for declaring an I/O objects in the Neuron C language is
shown below.
pin direction type [options] io-object-name;
pin
One of the Neuron C keywords that name one of the twelve I/O pins, IO_0
through IO_11 (pin IO_11 is available only on Series 3100 Power Line devices
and Series 5000 devices). The named pin defines the first pin for multi-pin
I/O objects. In general, pins can appear in a single object declaration only.
However, a pin can appear in multiple declarations of the bit, nibble, and
byte I/O object types. Also, IO_8 can appear in multiple declarations of
neurowire master specifying different select pins. In this case, it is not
required that all declarations have the same sense, that is, input or output;
see the
I/O Model Reference
.
direction
Specifies whether the pin is an input or an output. Some I/O objects are
bidirectional, and do not require the specification of direction.
type
Specifies the I/O object type.
Neuron C Programmer’s Guide 29
options
Optional I/O parameters, dependent on the chosen
The description of each object type includes the type’s available options.
Except where noted, these options can be listed in any order. All options
have default values that are used when you do not include the option in the
object declaration.
type
for the I/O object.
io-object-name
A user-supplied name for the I/O object, in the ANSI C format for variable
identifiers.
The description for each I/O object includes a detailed explanation of the syntax
for each I/O object type.
Example: A logic level needs to be measured at the IO3 input pin of the device,
which is named IO_3 in Neuron C. The pin is connected to a proximity detector,
as its programmatic name indicates.
IO_3 input bit ioProxDetector;
Whenever your program refers to the ioProxDetector variable, it is actually
referring to the logic level on pin IO3.
Some I/O objects can be combined or multiplexed according to specific rules. In
addition, there are a number of Neuron C functions and events predefined for
various I/O objects. See the
Neuron Chips
for more information about I/O objects.
I/O Model Reference for Smart Transceivers and
Device Self-Documentation
You can include a text string that describes your device in your application. This
text string can be accessed by any network management tool, and can be used by
a network integrator to verify that they have the correct device when designing
in or installing your device. This text string is appended to the device selfdocumentation (SD) string. The Neuron C compiler automatically generates a
portion of the SD string that documents the functional profiles that are
implemented by the functional blocks in your application. You can add
additional text for the SD string using the following compiler directive as
described in the
#pragma set_node_sd_string
Compiler Directives
chapter of the
C-string-const
Examples
This section presents three complete programs that illustrate Neuron C
capabilities and good coding style. The examples are:
1 Thermostat interface
2 Simple light dimmer interface
3 Seven-segment LED display interface
Neuron C Reference Guide
:
30 Focusing on a Single Device
Example 1: Thermostat Interface
This thermostat measures the resistance of a thermistor by measuring the pulsewidth of a waveform that is input to pin IO6. The I/O object declaration is set up
to measure the on-time of the waveform. A simple
yields the temperature.
T=mx+b
scaling of the on-time
ontime
The example also uses a shaft encoder generating a quadrature input as a dial to
select a new temperature setting (see
type is used with the io_update_occurs event. The input value of the input object
represents the change in rotational offset since the last input. Shaft encoders
typically generate offsets of 16 to 256 counts per 360 degrees rotation. The
io_update_occurs event evaluates to TRUE only when a nonzero offset has been
measured. In the following application, the task associated with the when
(io_update_occurs...) clause is executed only when the quadrature input dial has
moved from the previously measured position.
Figure 2). The quadrature input object
Figure 2. Sample Thermostat Device
The io_changes event would rarely be used with the quadrature I/O object,
because the event would evaluate to TRUE only when a
count occurred. The io_changes event would not evaluate to TRUE as long as the
input object were moving at a constant rate because the nonzero measurements
would be the same. This example is intended to illustrate use of typical I/O
objects. Network variable information has been omitted; it is covered in detail in
3,
Chapter
// THERMOS.NC -- LonWorks thermostat device
Neuron C Programmer’s Guide 31
How Devices Communicate Using Network Variables
change
in the measured
, on page 43.
// Uses a thermistor to measure temperature, and a
// quadrature encoder to enter setpoint. Activates either
// heating or cooling equipment via bit outputs.
///////////////// Include Files //////////////////
#include <stdlib.h>
// for muldiv()
////////////////////// Timers /////////////////
stimer repeating tmCheckHeatOrCool;
// Automatically repeating timer
////////////////// Constants ///////////////////////
#define TEMP_DEG_F(t) (((long)t - 32L) * 50 / 9 + 2740)
// macro to convert degrees F to SNVT_temp
const SNVT_temp DESIRED_TEMP_MAX = TEMP_DEG_F(84);
const SNVT_temp DESIRED_TEMP_MIN = TEMP_DEG_F(56);
const SNVT_temp BAND_SIZE = 10;
// Guardband of +/- 1 deg C around desired temperature
//////////////// Global Variables ////////////////////
SNVT_temp newTemp = TEMP_DEG_F(70);// init to 70 deg F
SNVT_temp desiredTemp = TEMP_DEG_F(70);
enum {
OFF, HEATING, COOLING
} equip = OFF; // current state of HVAC equipment
/////////////////// Tasks //////////////////////
// I/O update task -// read thermistor voltage-to-frequency converter
when (io_update_occurs(ioTempRaw)) {
// An update occurs periodically as the ontime is
// sampled. The new sample is placed in 'input_value.'
// Calculation is performed using 32-bit intermediate
// math, then the result stored as a SNVT_temp. The
// input is scaled based on the temperature coefficient
// of the thermistor.
newTemp = muldiv(input_value, 25000, 9216) + 2562;
}
/////////////////////////////////////////////////////
// I/O update task -- read quadrature encoder
// A quadrature input is used as a dial to select a new
// temperature setting.
when (io_update_occurs(ioShaftIn)) {
// An update occurs for a quadrature I/O object when the
// accumulated offset is nonzero. The value is placed in
// 'input_value' by the io_update_occurs event.
desiredTemp += input_value; // Assumes no overflow
desiredTemp = min(DESIRED_TEMP_MAX, desiredTemp);
32 Focusing on a Single Device
desiredTemp = max(DESIRED_TEMP_MIN, desiredTemp);
}
////////////////////////////////////////////////////////
// Timer task -- execute control algorithm
// A timer is used to decide periodically whether to
// activate heating or cooling. The temperature comparison
// is done only every five minutes to prevent cycling the
// equipment too frequently. There are two digital outputs:
// one for activating the heating equipment, and one for
// activating the cooling equipment.
when (timer_expires(tmCheckHeatOrCool)) {
switch (equip) {
case HEATING:
if (newTemp > desiredTemp) { // if too hot
equip = OFF; // turn off heater
io_out(ioHeatingOn, FALSE);
}
break;
case OFF:
if (newTemp < desiredTemp - BAND_SIZE) {
equip = HEATING; // if too cold, then
io_out(ioHeatingOn, TRUE); // turn on heater
} else if (newTemp > desiredTemp + BAND_SIZE) {
equip = COOLING; // if too hot, then
io_out(ioCoolingOn, TRUE); // turn on cooler
}
break;
case COOLING:
if (newTemp < desiredTemp) { // if too cold
equip = OFF; // turn off cooler
io_out(ioCoolingOn, FALSE);
}
break;
}
}
///////////////////////////////////////////////////////
// Reset task -- Set the repeating timer to 300 seconds
The following example shows Neuron C code for a simple light dimmer. The
example uses two I/O objects, a triac control circuit to control the lamp brightness
and a quadrature input to select the light level (see
triac output object, a value of 1 is maximum brightness, and a value of 320 is
minimum brightness (OFF) when the line frequency is 60 Hz. The initial value
on power-up is full OFF (65535).
The io_update_occurs event is used in a when clause. An implicit call to io_in( )
occurs when this event is called. The program can then access the measured
Neuron C Programmer’s Guide 33
Figure 3 on page 34). For the
value through the built-in variable input_value.
Dimmer Switch
Zero-Crossing
Detector
110VAC
Triac
Trigger
Shaft
Encoder
Neuron
Chip
IO_6
IO_0
IO_4
IO_5
Figure 3. Simple Dimmer Device
// DIMMER.NC -- LonWorks triac dimmer control
// Uses a triac output to control an incandescent lamp
// Uses a shaft encoder input to set desired lighting level
//////////////////////// Constants /////////////////////
// These constants are appropriate for 60Hz line frequency
const unsigned long MIN_BRIGHTNESS = 320;
const unsigned long MAX_BRIGHTNESS = 1;
///////////////////// Global Variables /////////////////
signed long currentBrightness;
// Reset task -- turn the lamp off
when (reset) {
io_out(ioLampTriac, MIN_BRIGHTNESS);
currentBrightness = MIN_BRIGHTNESS;
}
// I/O update task -- read quadrature input dial
// to select the light level
when (io_update_occurs(ioShaftIn)) {
// An update occurs for a quadrature input
// object when the accumulated offset is
// nonzero. The sample value is in
// 'input_value'. The value is subtracted
34 Focusing on a Single Device
// since a lower value means more light.
currentBrightness -= input_value;
// Look for underflow or overflow
if (currentBrightness < MAX_BRIGHTNESS)
currentBrightness = MAX_BRIGHTNESS;
else if (currentBrightness > MIN_BRIGHTNESS)
currentBrightness = MIN_BRIGHTNESS;
// Change the triac setting to the
// desired brightness level
io_out(ioLampTriac, currentBrightness);
}
Example 3: Seven-Segment LED Display Interface
The following example shows how to connect multi-character displays to the
neurowire port. The display has an 8-bit configuration register and a 24-bit
display register. This configuration can be defined as follows:
Note that the figure does not show pull-up resistors for the IO_2, IO_8, or IO_9
pins; for a Series 3100 device, you can use the #pragma enable_io_pullups
directive to add pull-ups to these pins; for a Series 5000 device, you need to add
external pull-up resistors for the pins.
Input Clock Frequency and Timer Accuracy
Depending on the manufacturer and version, the Neuron Chip and Smart
Transceiver system clock frequencies are 80 MHz, 40 MHz, 20 MHz, 10 MHz,
6.5536 MHz, 5 MHz, 2.5 MHz, 1.25 MHz, and 625 kHz. Certain timers listed
below are
fixed timers
; that is, they have the same absolute duration regardless
of the input clock selected. However, the slower the system clock, the less
accurate the timer.
Scaled timers
, also listed below, scale in proportion to the
input clock.
Fixed Timers
In general, timers discussed in this manual are of fixed duration unless noted
otherwise. The following timers are implemented in hardware and have periods
that are independent of the Neuron Chip or Smart Transceiver input clock
frequency. However, the accuracy of these timers is determined by the accuracy
and frequency of the input clock for the Neuron Chip or Smart Transceiver.
• Preemption mode timeout timer.
• Pulsecount input timer. Timer used to determine the counting interval
for the pulsecount input object. The interval is (223)/107 (approximately
0.8388608) seconds.
36 Focusing on a Single Device
•Triac pulse timer. Timer used to generate pulses for the stretchedtriac
and triac output objects.
The following timers are implemented in software and have periods that are
independent of the Neuron Chip or Smart Transceiver input clock. The accuracy
of these timers is discussed in the next section.
•Application second timer (that is, an stimer declared in a Neuron C
program).
•Application millisecond timer (that is, an mtimer declared in a Neuron C
program).
Scaled Timers and I/O Objects
Timers and I/O objects that scale with the input clock are directly proportional to
the input clock. For example, a serial object configured at 2400 bps would
actually run at 600 bps given a 2.5 MHz (1/4 speed) input clock. The following
timers scale with the input clock:
• bitshift clock
• neurowire master clock
• serial clock
• watchdog timer (only scales for Series 3100 devices)
Note: The configurable EEPROM write timer accuracy is affected by the input
clock. See
EEPROM Write Timer
on page 41 for more information.
Calculating Accuracy for Software Timers
This section describes the accuracy of the millisecond and second timers for
various system clock rates.
Accuracy of Millisecond Timers
The following formulas define the range of accuracy for a millisecond timer.
Accuracy is expressed as a low and high duration. The low duration
minimum time from when a timer is set to when the system posts an event for
(H)
the application. The high duration
is set to when an event is posted.
the expected duration.
The added delay to detect the expiration event, that is, the
not
of the application and is
posted while the application is executing a task associated with a when clause is
be detected until the executing task completes and returns control of the
application to the scheduler.
included in these formulas. For example, an event
is the maximum time from when a timer
L
and H are expressed below as a function of E,
latency
(L)
is the
, is a function
:
When an event is posted by the Neuron firmware, it becomes visible to the
Note
scheduler and to other events (for example, io_changes, nv_update_occurs).
With a 10 MHz Input Clock
In the following formula, the
greater than the argument, for example,
Neuron C Programmer’s Guide 37
floor( )
function returns the largest integer not
floor(
3.3) = 3 or
floor
(3.0) = 3. For a
Series 3100 device with a 10 MHz clock, the expected duration of a millisecond
timer is:
E
= 0.8192 *
floor
((D/0.82) + 1)
where
ms,
For a Series 3100 device with a 10 MHz clock with a 10 MHz clock, the low
duration is:
and the high duration is:
D
is the specified duration for the timer. For example, for a timeout of 100
E
equals 99.94 ms.
L = E
– 12 ms
H
= E + 12 ms
With Other Clock Speeds
The following formulas allow you to calculate accuracy for millisecond timers
S
when other input clock rates are selected. In these formulas,
input clock rate or the system clock rate, as shown in
Table 5. Determining S
Input Clock Rate
S
0.063 — 80 MHz
0.125 — 40 MHz
(Series 3100)
Table 5.
System Clock Rate
(Series 5000)
depends on the
0.25 40 MHz 20 MHz
0.5 20 MHz 10 MHz
1 10 MHz 5 MHz
1.5259 6.5536 MHz —
2 5 MHz —
4 2.5 MHz —
8 1.25 MHz —
16 625 kHz —
E
= 0.8192 * floor ( (floor(
Two factors determine
less granular the input clock. For example, at 1/16 speed, the millisecond
granularity is 16 milliseconds (one clock tick every 16 milliseconds). The second
factor is that the hardware generates 819.2 microsecond ticks that the software
D/S)*S
E.
The first is that the slower the input clock speed, the
)/0.82) +1 )
38 Focusing on a Single Device
treats as 820 microsecond ticks. This means that a timer duration is actually
0.999 times the specified duration.
For example, for a Series 3100 device with a 2.5 MHz clock, a specified timeout of
99 ms would result in an expected duration of 96.67 ms.
The complete formulas for calculating the low and high durations are:
L = E
- (11*S + 1)
H = E
+ (11*S + 1)
The high duration with a 2.5 MHz clock and a specified timeout of 99 ms would
thus equal 141.67 ms; the low duration is 51.67.
Note: The number "11" in the formulas above is based on a typical worst case
scenario. In the absolute worst case, that is, the maximum number of timers,
network variables, addresses, and so on, this number can be as high as 32.
In addition, the high duration may be increased by
(NMD), an additional skew introduced by network management message
processing. Normally, this term is 0. But, if a device were to process a network
management message, the upper range for any given timeout could be
significantly increased. For example, adding a domain to a device would result in
an NMD of anywhere from 300 ms to (300 + 838*
management operations of this type occur infrequently. It is always good
practice to take a device offline, if possible, before sending further network
management messages.
To measure an event’s duration, a timer can be polled before and after the event,
and the difference can be calculated. To measure the duration of events less than
50 milliseconds, use the get_tick_count( ) function instead of the software timers
(see the
Neuron C Reference Guide
).
network management delay
S
) ms. In general, network
Repeating Timers
For repeating timers, there is no cumulative drift other than that produced by
D
the difference in
LR
range of
ER = E * N
and
LR
to HR, where:
= ER - (11*S + 1)
and E. The Nth timeout for repeating timers occurs in the
HR
= ER + (11*S + 1)
For repeating timers, intermediate timeout events are lost if the following is true:
abs
(AR
- ER ) ≥
ER
- AR >
where AR is the actual duration of the repeating timer.
Neuron C Programmer’s Guide 39
E
E
H1
E1
L1
H2
E2
L2
Time started here.
Figure 5. Expected, Low, and High Duration of Timeout Events
Accuracy of Second Timers
The second timers rely on the one-second timer, which is based on the millisecond
timer mechanism described earlier. A one-second timer of duration
in the range of
using the millisecond timer duration formulas for
E1
Timer expires in this range.
Second iteration of timer expires in this range.
D
times out
D
-1 to D seconds, where “second” is defined as 1001 milliseconds
L
and H.
For example, at 625 kHz, each “second” is 991.23 milliseconds. Thus a 10-second
timer would time out in the range of 8.74 to 10.09 seconds.
For repeating one-second timers, the first timeout occurs in the range of
D
seconds. Subsequent timeouts occur every
repeating 10-second timer would occur in the range of 48.39 to 49.74 seconds.
seconds. The fifth timeout of a
D
-1 to D
Delay Functions
Three functions allow an application to perform timing directly by suspending
execution for a given time. These functions provide a concise way to perform
timing in-line:
delay( )
msec_delay( )
scaled_delay( )
The delay( ) function produces a delay of fixed duration that is independent of
input clock speed. This function can be used with the wink feature and for I/O
debouncing. Its prototype is the following:
void delay (unsigned long
40 Focusing on a Single Device
count
);
count
A value between 1 and 33,333. See the
the formula used in determining the duration of the delay. Values in
the range 33,334 .. 65,535 can be specified, but cause a watchdog
timer reset.
Example:
when (io_changes(io_switch))
{
delay(400); // wait 10msec for debounce
.
.
.
}
The msec_delay( ) function produces a delay of a fixed number of milliseconds
independent of the input clock speed. This function can be used with to delay for
a more precise, and shorter, period of time than the delay( ) and scaled_delay( )
functions. Its prototype is shown below:
Neuron C Reference Guide
for
void msec_delay (unsigned short
milliseconds
The scaled_delay( ) function produces a delay with a duration that scales with
input clock speed. Its syntax is:
void scaled_delay (unsigned long
count
A value between 1 and 33,333. See the
A number of milliseconds to delay (max of 255 ms).
the formula used in determining the duration of the delay.
EEPROM Write Timer
The accuracy of the configurable EEPROM write timer degrades with the speed
of the input clock. To determine the accuracy of an
formula:
n
duration =
For example, for a Series 3100 device at 625 kHz, a 20 millisecond EEPROM
write actually takes 55.2 milliseconds.
* delay(43)
milliseconds
count
);
);
Neuron C Reference Guide
n
millisecond timeout, use the
for
Neuron C Programmer’s Guide 41
How Devices Communicate Using
Network Variables
This chapter discusses how LONWORKS devices communicate with
each other using network variables. It includes a detailed discussion
of how to declare network variables and how network variables on
different devices are connected to each other. The use of synchronous
network variables, the process of polling network variables,
authenticated network variables, and network variables that
implement a changeable type are also described.
3
Neuron C Programmer’s Guide 43
Major Topics
LONWORKS devices communicate with other LONWORKS devices through network
variables or application messages. This chapter focuses on network variables,
which provide an open interoperable interface, simplify programming and
installation, and also reduce program memory requirements. Most Neuron C
programs use network variables. Application messages can be used, if required,
as described in Chapter
Messages
separately, a single Neuron C program can use both network variables and
application messages.
This chapter is divided into the following parts:
, on page 117. Although this manual discusses the two methods
6,
How Devices Communicate Using Application
Overview
•
and writers of a network variable, as well as how network variables are
declared. It also describes how network variables on different devices are
connected to each other.
Declaring Network Variables
•
declaring network variables, along with related concepts.
Connecting Network Variables
•
variable readers are connected to network variable writers. This process
was described in general terms in Chapter
•
Network Variable Events
scheduling events that are related to network variables:
nv_update_completes, nv_update_fails, nv_update_occurs, and
nv_update_succeeds.
Synchronous Network Variables
•
synchronous network variables.
Processing Completion Events for Network Variables
•
describes the two modes of checking for completion events, and the
guidelines for use of these different techniques within an application
program.
Polling Network Variables
•
poll the writer device for the latest value of a network variable.
on page 45 summarizes the behavior of devices that are readers
on page 47 describes the syntax for
on page 49 describes how network
1,
Overview
on page 51 describes the following four
on page 53 describes the behavior of
on page 56 describes how a reader device can
.
on page 55
Explicit Propagation of Network Variables
•
application program may exercise explicit control over network variable
propagation, instead of permitting the Neuron firmware scheduler to
propagate network variable updates automatically.
Initial Value Updates for Input Network Variables
•
when and how to manage initial values for input network variables.
Monitoring Network Variables
•
considerations for implementation of a monitoring device.
Authentication
•
variables to increase network security. Authentication allows a reader to
verify the identity of a writer that attempts to update the reader’s value
of the network variable. Authentication can also prevent unauthorized
configuration of a device.
44 How Devices Communicate Using Network Variables
on page 66 describes how to use authenticated network
on page 65 describes special
on page 60 describes how an
on page 62 describes
•
Overview
Changeable-Type Network Variables
implement network variables that allow their type to be changed at
installation time.
on page 68 describes how to
As described in Chapter 1,
represents a data value and may be connected to multiple devices on a network.
How many network variables a Neuron-hosted device can support depends on the
device’s memory map, the system firmware, and the development tool version, as
shown in
Neuron System
Firmware Version
Version 15 or earlier Any 62
Version 16 or later
The maximum number of network variables for applications developed with the
Mini EVK Evaluation Kit or the Mini FX Evaluation Kit is 32. The limits for
host-based applications depend on the development product used.
Important: The NodeBuilder CodeWizard declares network variables so that
they are placed in RAMNEAR memory by default. However, because of the
larger number of network variables that are available for devices built with the
NodeBuilder FX Development Tool, your device could run out of available
RAMNEAR memory. In this case, declare as many network variables as
necessary to use RAMFAR memory:
Table 6.
Overview
Table 6. Network Variable Limits
NodeBuilder
Development Tool
Version
3.1 or earlier 62
FX or later 254
, a network variable is an object that
Maximum Number of
Network Variables
1. Within the NodeBuilder CodeWizard, right-click the network variable
and select Properties to open the NV Properties dialog.
2. Within the NV Properties dialog, click Advanced to open the Advanced
NV Properties dialog.
3. Within the Advanced NV Properties dialog, select far. Click OK to close
the dialog.
4. Within the NV Properties dialog, click OK to close the dialog.
Network variables are defined within the program that runs on an individual
Neuron Chip or Smart Transceiver. As an example, consider a lamp program
with one network variable, named nviLamp (see
consider a switch program with one network variable, named nvoSwitch. The
same lamp program is installed on each of the three lamp devices, and the same
switch program is installed on each of the two switch devices in the figure.
Neuron C Programmer’s Guide 45
Figure 6 on page 46). Also,
Figure 6. Sample Development Network with Five Devices
The declarations for these two network variables, which appear in different
programs, are the following:
network output SNVT_switch nvoSwitch;
and
network input SNVT_switch nviLamp;
Behavior of Writer and Reader Devices
A writer device can change the value of a network variable. The connected
network variables in all reader devices are then updated to reflect this change.
In general, a reader device only reads from its copy of the network variable. One
exception is that a reader device can provide an initial value to the network
variable when the variable is declared. Another exception is that a reader device
can modify its local copy of a network variable in its program. However, in
neither case is the new value propagated to any other devices.
A writer device can also read from its last copy of the network variable, but it
only sees the value it wrote last. In other words, two writers of the same network
variable cannot change each other’s value.
When a writer device writes a value to an output network variable, the Neuron
firmware causes a L
informing them of the new value. By default, the message is sent using the
acknowledged (ACKD) service. Not all readers may receive updates
simultaneously. The network application must be designed to handle update
failures and delays.
ONWORKS message to be sent to all readers of the variable,
46 How Devices Communicate Using Network Variables
Note: This discussion uses the terms
device is a device that writes to a particular network variable (an output network
variable). A reader device is a device that reads a particular network variable
(an input network variable). In many cases, a device has both input and output
network variables declared in its program, and therefore acts both as a “writer
device” and a “reader device,” depending on the network variable.
When Updates Occur
The new value of a network variable received by a reader device does not take
effect immediately upon reception and processing of the message. Similarly,
assignment of a new value to an output network variable does not cause a
message to be sent immediately. Rather, updates occur at the end of a critical
section in the application program. A
application program statements during which network variable updates are not
propagated.
A task is an example of a critical section: once begun, each task runs to
completion. When network variable updates are received or requested, they are
posted by the scheduler at the end of each critical section. An application can use
the post_events( ) function to divide a single task into two or more critical
sections. The post_events( ) function can be used to increase throughput and
improve response time since it forms a boundary at which outgoing network
variable updates are sent and incoming network variable updates are processed.
7,
See Chapter
post_events( ).
Additional Features
writer device
critical section
, on page 145, for further discussion of
and
reader device
is defined as a set of
. A writer
Declaring Network Variables
The syntax for declaring a network variable is shown below. The first form of the
declaration is for a simple network variable, and the second form is for a network
variable array.
network input | output [
[
[ =
network input | output [
[
[ =
Note: The brackets around the term
optional field. They are required and must be part of the program.
A Neuron-hosted device can declare up to 254 network variables (including array
elements), but the device’s resource capacity (as defined by its memory map)
might not support the maximum number of network variables.
You can declare an array of network variables using the second form of the
syntax shown above. The array can only be single dimension. The
must be a constant. Each element of the array is treated as a separate network
variable for purposes of events, transmissions on the network, and so on.
Therefore, each element counts individually towards the maximum number of
network variables on a given device. Each element of the array is then a
connection-info] identifier
initial-value
connection-info] identifier [array-bound
initializer-list
separately bindable
netvar-modifier
] [
nv-property-list
netvar-modifier
] [nv-
property-list
network variable.
array-bound
] [
class] type
] ;
] [
class] type
] ;
]
do not, in this case, indicate an
array-bound
Neuron C Programmer’s Guide 47
After the device design is complete, you specify connections between network
variable outputs and inputs on different devices. This is discussed in
Network Variables
used by a network tool to generate the appropriate network addresses. When
these addresses are downloaded into the devices, they ensure that updates sent
by writers reach all of the intended readers.
on page 49. The specification of the desired connections is
Connecting
In the lamp and switch example shown in
network variables in column 1 are connected to the input network variables in
column 2, as listed in
When a network variable that is a structure is modified by a network variable
writer, the entire structure is updated at the next critical section boundary for all
network variable readers, regardless of whether the structure was wholly or
partially modified.
Network variables can be declared with a single dimension array bound. Each
element of the array is then a separately bindable network variable. See the
descriptions of the poll( ) function, the built-in nv_array_index variable, and the
nv_update_completes, nv_update_fails, nv_update_occurs, and
nv_update_succeeds events in the
information.
When an element of a network variable that is an array is modified by a network
variable writer, only the modified element is updated at the next critical section.
Table 7.
Neuron C Reference Guide
Figure 6 on page 46, the output
lamp2/nviLamp
for more
The maximum size of a network variable is 31 bytes. In the case of a network
variable array, each element is limited to a size of 31 bytes.
The Neuron C compiler includes the SNVT indices (numerical identifiers for the
standard network variable types) in the application image for all network
variables declared as SNVTs, and optionally also includes the network variable
names for all network variables. Network variable names are always included in
the device interface file for a device, but integrators might find them useful when
they lose the device interface file and need to install your device. You can control
these options using the following compiler directives as described in the
Directives
See the
for declaring a network variable.
chapter of the
#pragma disable_snvt_si
#pragma enable_sd_nv_names
Neuron C Reference Guide
Neuron C Reference Guide
for additional information about the syntax
:
Compiler
Examples of Network Variable Declarations
Some sample network variable declarations are the following:
48 How Devices Communicate Using Network Variables
The unacknowledged service can be used for this network variable because we
can assume that the control dial generates numerous messages as it is being
turned, and you probably don’t need or want to receive an acknowledgment for
each one. In addition, it is probably not critical to this application if a single
message out of several is not received.
Connecting Network Variables
Network variable
device. Network variable connections are created by a portion of a network tool
called the
another network tool.
The binder assigns addresses and transport properties, such as timer values, to
all appropriate devices to ensure that information flows to and from the right
places.
Example: Binding output network variables to input network variables creates a
“closed-loop system”, also sometimes called a “servo system”. By connecting the
network variables of two or more devices, you allow the system to use feedback or
error-correction signals from one device to set or maintain the control mechanical
position or other parameters of the other device.
simple closed-loop system for a stairwell lighting system.
In the figure, the dashed line represents the “forward” connection that drives the
lamp from both switches. The lamp reports its current on/off state and dimming
level through the solid line that represents the feedback connection to the
switches, which allows all components of the stairwell lighting system to be
aware of current lighting conditions.
binder
connections
. The binder can be part of the LonMaker Integration Tool or
are independent of the Neuron C application on a
Figure 7 on page 50 shows a
Neuron C Programmer’s Guide 49
Figure 7. A Simple Closed-Loop System
Use of the is_bound( ) Function
A typical application need not know where local output network variables are
connected, and need not know the source of updates to local input network
variables. While such detail is available where necessary, typical applications
can focus on the semantics of the input network variable update and the local
control algorithm.
When necessary, a Neuron C application can determine if a network variable has
been connected by a network tool by calling the is_bound( ) function. For
example, a device might expect periodic updates to a local input network variable
under normal circumstances, and might enter a failure mode if such updates fail
to arrive for a prolonged amount of time. Such an application could then use the
io_bound( ) function as a predicate to disable or enable certain aspects of the
application algorithm.
Whenever an unconnected output network variable is updated, an
nv_update_succeeds event becomes TRUE even though no update actually
occurred (see also
55).
The is_bound( ) function only indicates whether the network variable is bound or
unbound. Another device, such as a network tool for monitoring and control, may
still attempt to obtain the current value of an unbound output network variable
by polling, or may still update an unbound input network variable by setting its
value without a bound connection. Thus, reducing the application’s processing
requirements by conditional processing based on the is_bound( ) function should
be limited to those devices that cannot operate without a bound connection, such
as devices implementing a closed-loop system.
Processing Completion Events for Network Variables
on page
50 How Devices Communicate Using Network Variables
Network Variable Events
Chapter 2,
scheduling mechanism and discussed a number of predefined events. Four
predefined events are specifically related to network variables:
The nv_update_occurs event applies only to input network variables. The other
three events (nv_update_completes, nv_update_fails, nv_update_succeeds) apply
to output network variables when they are updated, and to input network
variables when they are polled.
The event expression may be qualified with a
be a network variable name, a network variable array element (as in
[
index
var
the event is qualified by an array name, the event occurs once for each element
for which the event is applicable.
The form of the event that permits a range of network variables has the syntax
shown below. The range consists of two network variable or network variable
element references, separated by two consecutive dot characters ".." indicating
the range. This syntax applies to all four
network variable is assigned a global index by the compiler. An array of network
variables is assigned consecutive indices, one for each element. The range event
applies to all network variables whose global indices are between the global index
nvA
for
index of
Focusing on a Single Device
network-var-reference
network-var-reference
network-var-reference
network-var-reference
, on page 15, introduced the event
)]
)]
)]
)]
network-var-reference
, which can
network-
]), a network variable array name, or a range of network variables. If
and
nvB
nvB
, inclusive. The global index of
.
event-names
nvA
shown above. Each
must be less than the global
event-name
This section provides an introduction to these events. For convenience, we refer
to them as network variable
whether or not a network variable update or poll has completed. Note that
completion does not imply success. See also Chapter
[(
nvA .. nvB)]
completion events
Communicate Using Application Messages
detailed information on using these completion events.
The nv_update_occurs Event
When a new value has been received for an input network variable, the
nv_update_occurs event evaluates to TRUE. If a specific network variable is not
used to qualify the event, it evaluates to TRUE for any network variable update
on that device.
The nv_update_occurs event is used in many situations. For example, a lamp
program could use this event as follows:
// Use the network variable’s value
// as the new state for the lamp
network input SNVT_switch nviLampState;
when (nv_update_occurs(nviLampState)) {
, because they all pertain to
6,
How Devices
, on page 117, which includes more
Neuron C Programmer’s Guide 51
io_out(ioLED, nviLampState.state);
}
In the following example, when a thermostat device receives a new temperature
setpoint, it checks the current temperature and turns the heater on or off if
necessary:
Most applications do not need to know the source of an input network variable
update, and can focus on implementing behavior in response to receiving the
updated network variable value.
However, the nv_in_addr built-in variable, described in the
, provides addressing information about the device that originated the
Guide
update.
Neuron C Reference
The nv_update_succeeds and nv_update_fails
Events
When a network variable update or poll fails, the nv_update_fails event
evaluates to TRUE. If no network variable is specified for the event, it evaluates
to TRUE for any network variable update or poll that failed on that device. If
multiple network variables are specified, the event can be TRUE once for each
network variable update or poll that failed.
Similarly, the nv_update_succeeds event evaluates to TRUE whenever an output
network variable update has been successfully sent or polled values have been
received from all the writers.
You can use the nv_update_fails event for any output network variables. The
following example illustrates using the nv_update_fails event with a single
output network variable:
network output SNVT_switch nvoSwitch;
when (nv_update_fails(nvoSwitch))
{
// take some corrective action
}
Here is an example of testing for network update failure and success:
52 How Devices Communicate Using Network Variables
heater_failed = FALSE;
// heater device received update
}
The nv_update_completes Event
The nv_update_completes event evaluates to TRUE whenever an output network
variable update or poll either succeeds or fails. An example of testing for
network variable update completion is shown below:
#include <io_types.h>
#define C_TO_K 2740
IO_7 input ontime invert clock(2) io_temperature_sensor;
network output SNVT_temp nvoCurrentTemp;
when (nv_update_completes(nvoCurrentTemp))
{ // latest temperature has been sent out
ontime_t sensor_value;
// send another update
sensor_value = io_in(io_temperature_sensor);
nvoCurrentTemp = (sensor_value * 221) / 642
+ 211 + C_TO_K;
// tenths of a degree,C
}
If a program checks for nv_update_completes or nv_update_succeeds for any
network variable, the program is said to use comprehensive completion event
testing. See
you should follow.
Comprehensive Completion Event Testing
Synchronous Network Variables
When an output network variable is updated, the Neuron firmware ensures that
the most recent value assigned to an output is propagated and received as an
event by any connected input network variables. Thus, if multiple updates are
made to an output network variable within the same critical section, only the last
value assigned is ensured to be propagated and received as an event at the input
network variables.
A critical section is defined by the boundaries of the executing when task. After
the when task completes, the most recent value is scheduled for propagation.
all
You can specify that
section) must be propagated and received as events by using the
subclass of network variables.
However, for a synchronous output network variable, each updated value is
immediately scheduled for propagation, which requires an application output
buffer for each scheduled update. If all output buffers are already in use when an
update to a synchronous output network variable is scheduled, the Neuron
firmware enters preemption mode to attempt to complete pending transactions
and thus free in-use application output buffers.
updates to an output network variable (within the critical
on page 55 for the rules
synchronous
As a result, updating synchronous output network variables can cause your when
task to execute in a non-deterministic fashion. See
for more information about buffers and preemption mode.
Neuron C Programmer’s Guide 53
Preemption Mode
on page 55
Declaring Synchronous Network Variables
To declare a synchronous network variable, include a synchronized or sync
keyword in its declaration. An example declaration is shown below:
network output sync SNVT_temp nvoRelativeTemp;
In the following example, the network variable is declared as synchronous so that
all the updates are sent. (If more than one alarm goes off, we want to receive
notice of all alarms, not just the most recent one.)
Synchronous output network variables do not have to be connected to
synchronous input network variables. All input network variables operate
synchronously regardless of whether the synchronous attribute was assigned.
Synchronous vs. Nonsynchronous Network Variables
For most applications, nonsynchronous network variables are adequate and
recent
should be used when possible. Many applications need the most
all of the values, for a given network variable. Widespread use of synchronous
network variables that are frequently updated could delay processing if the
program frequently runs out of buffers (see
Depending on the device buffering, channel speed, and congestion of the network,
application performance could be adversely affected by extensive use of
synchronous network variables.
Preemption Mode
on page 55).
value, not
If a program is required to use
network variables might be necessary to preserve the intermediate data values.
For programs using
usually sufficient.
A nonsynchronous output network variable goes out on the network when the
next output buffer is available. If the program updates the variable again before
that time, only the most recent value goes out. A synchronous output network
variable causes the application to wait for an output buffer if none is available.
In this case, the scheduler enters preemption mode (see
55).
page
For input network variables, an incoming network variable update always
results in an event for the application. All input network variables operate
synchronously regardless of whether the synchronous attribute was assigned.
absolute
relative
data values, nonsynchronous network variables are
(or
delta
) data values, synchronous
Preemption Mode
Updating Synchronous Network Variables
Synchronous network variables are always updated at the end of each critical
section. If a buffer is not available, the scheduler waits for one. Nonsynchronous
network variables, on the other hand, are updated at the end of critical sections
when the scheduler has application buffers available to do so. Unlike
synchronous network variables, they are not always updated at the end of the
next critical section. As already pointed out, where multiple updates occur, the
intermediate values might never be propagated across the network.
on
54 How Devices Communicate Using Network Variables
Preemption Mode
The scheduler enters
variable update occurs and there is no application output buffer available.
Because the system must send out the synchronous output network variable
update, it processes completion events, incoming msg_arrives or
nv_update_occurs events, and response events until an application output buffer
becomes available.
Other events are not processed, unless the when clause for the event is preceded
by the keyword preempt_safe. See Chapter
15, for the syntax of a when clause. See Chapter 6,
page
Communicate Using Application Messages
of preemption mode, and when to use the preempt_safe keyword.
A delay in application processing thus occurs when the system enters preemption
mode. The length of the delay depends on how long it takes for an application
output buffer to become free. This delay depends on network traffic, channel bit
rate, and other factors.
preemption mode
when a synchronous output network
2,
Focusing on a Single Device
How Devices
, on page 117, for a further discussion
Processing Completion Events for Network
Variables
For network variables, there are two modes of checking for completion events:
partial completion event testing, and comprehensive completion event testing.
6,
For message tags (see Chapter Chapter
Application Messages
is available.
, on page 117), only comprehensive completion event testing
How Devices Communicate Using
, on
Partial Completion Event Testing
If you choose to use partial completion event testing in your program, you then
have two choices of how to process completion events for each network variable:
1 Do not check for any completion events.
2 Check for only the failure event (nv_update_fails).
For example, within a program containing two network variables:
• Network Variable 1: Program checks for no completion events.
• Network Variable 2: Program checks for failure only.
Comprehensive Completion Event Testing
Comprehensive completion event testing offers the same set of choices for
network variable completion events that is available for processing message tag
6,
completion events (see Chapter
Messages
testing in your program, you then have three choices of how to process completion
events for each network variable:
1 Do not check for any completion events.
, on page 117). If you choose to use comprehensive completion event
How Devices Communicate Using Application
Neuron C Programmer’s Guide 55
2 Check for the failure and the success events
(nv_update_fails, nv_update_succeeds).
3 Check for the update completion event (nv_update_completes).
For example, the following is an acceptable strategy within a program containing
three network variables:
• Network Variable 1: Program checks for no completion events.
• Network Variable 2: Program checks for failure and success.
• Network Variable 3: Program checks for update completion only.
Note: If you choose to use comprehensive completion event testing features (with
network variables), all completion code processing for network variables must be
comprehensive completion event testing. This restriction does
events must be checked for all network variables; it only means that a single
program can use
cannot intermix both techniques. The Neuron C compiler detects use of the
comprehensive event feature on a
Tradeoffs
Using comprehensive completion event testing for processing network variable
completion events within a program requires more code space and is less efficient
than using partial completion event testing. If you choose a comprehensive
completion event testing feature, such as checking nv_update_completes, you are
limited to comprehensive completion event testing features for whichever
network variable’s events in which you are interested. For example, within a
program using comprehensive completion event testing, you cannot simply check
for nv_update_fails, because that feature applies only to partial completion event
testing.
not
either
partial or comprehensive completion event testing, but
per-program
basis.
mean that
Polling Network Variables
As described earlier in this chapter, a network variable update is normally
initiated when a device assigns a value to an output network variable. Another
device can request that the first device send its latest value for a network
variable. The process of requesting current network variable values from a
device is called
A device’s program can poll any input network variables at any time, including
initial power-up and when transitioning from offline to online. Polling on initial
power-up can cause network congestion if many devices are powered-up at the
same time, and they all do power-up polling. See
polling
Network Variables
up and reset processing.
Polling an input network variable from your program requires the network
binder to apply a different scheme when connecting output network variables
between writer and reader devices, requiring additional address table entries to
be used on the reader device. If you add polling to an existing application that
did not previously use polling, you must create a new device interface (XIF) file
for the device, and import the new device interface file into any network tools
that used the previous version.
56 How Devices Communicate Using Network Variables
.
Initial Value Updates for Input
on page 62 for more information about polling during power-
The reader device makes its request through the poll( ) function. The syntax is
shown below:
poll ([
network-var
]);
network-var
If no network variable is specified, all input network variables for the device are
polled. For Neuron-hosted applications, an explicit polled declaration is not
allowed for an input network variable; see
as Polled
The
element of a network variable array, as in
variable array name is used without an index, all elements of the array are
polled.
The new value resulting from the poll is not immediately available after the
poll( ) function call. Use a qualified nv_update_occurs event in a when clause, or
some other conditional statement, to obtain the new, polled value.
Example:
on page 58.
network-var
mtimer tDelayedPolling;
network input SNVT_switch nviCooling;
when (reset) {
// set up timer for delayed power-up polling:
tDelayedPolling = 4ul * random(); // >= 1 second
... // other reset processing
}
when (timer_expires(tDelayedPolling)) {
poll(nviCooling);
...
}
when (nv_update_occurs(nviCooling)) {
...
}
identifier can also be a network variable array identifier, or an
is an input network variable identifier.
Declaring an Input Network Variable
network_var[index
]. If a network
Here is a lamp program that includes a poll of the input network variable
nviLampState after a reset event. The device obtains the most recent value of
nviLampState, and then uses that value after reset.
// LAMP.NC -- Sample lamp actuator program,
// polls the switch on reset
/////////////////////// I/O Objects ////////////////////
IO_0 output bit ioLED = LED_OFF;
Neuron C Programmer’s Guide 57
mtimer tDelayedPolling;
/////////////////////////// Tasks //////////////////////
// NV update task -- handle update to lamp state
// Use the network variable’s value as the new state
// for the lamp
when (nv_update_occurs(nviLampState)) {
io_out(ioLED,
nviLampState.value && nviLampState.state
? LED_ON : LED_OFF);
}
when (reset) {
// set up timer for delayed power-up polling:
tDelayedPolling = 4ul * random(); // >= 1 second
... // other reset processing
}
when (timer_expires(tDelayedPolling)) {
poll(nviLampState);
}
Declaring an Input Network Variable as Polled
For Neuron-hosted applications, you cannot declare in input network variable as
polled; the Neuron C compiler issues an error message for polled input network
variables.
However, within a model file for a host-based application (such as for a
i
ShortStack, FTXL, or
network variable as polled:
network input polled
For host-based applications, the application code is written in a language other
than Neuron C, and therefore the presence of the poll( ) function within the
application would not cause the compiler to adjust the device’s self-identification
data to allow the network tool to create the network variable binding
appropriately. Thus, within a model file, the declaration of the input network
variable is allowed to be declared as polled so that the ShortStack Micro Server,
FTXL LonTalk protocol stack, or
variable to be polled.
.LON SmartServer application), you can declare an input
type netvar
;
i
.LON SmartServer can allow the network
Declaring an Output Network Variable as Polled
To allow devices to receive network variable updates from other devices only at
specified times, declare the output network variable as polled:
network output polled
In this special case, the output network variable’s value is never propagated as a
result of its value changing. Instead, the output network variable’s value is sent
only
in response to a poll request from a reader device, or if the propagate( )
function is called for that network variable.
type netvar
;
58 How Devices Communicate Using Network Variables
Example:
A lamp and switch example could also be written to use explicit polling of the
switch network variable. Complete programs illustrating polling are shown
below.
/////////////////////////// Tasks //////////////////////
// NV update task -- handle update to lamp state
// Use the network variable’s value as the new
// state for the lamp
when (nv_update_occurs(nviLampState)) {
io_out(ioLED,
nviLampState.value && nviLampState.state
? LED_ON : LED_OFF);
tmPoll = 500; // Wait 500 msec before polling again
}
////////////////////////////////////////////////////////
// Reset and timer task
// request last value from any switch attached
when (reset) {
tmPoll = 4ul * random(); // >= 1 second
}
when (timer_expires(tmPoll) ) {
poll(nviLampState);
}
Listing 2. Switch Program Using Polling
// SWITCH.NC -- Sample switch sensor program
// Only transmits switch state when polled by the lamp
/////////////////////////// Tasks //////////////////////
// I/O task -- handle pushbutton down event
// Just toggle the network variable (nvoSwitchState).
// In this case, no message is sent until a poll request
// is received from a reader device
when (io_changes(ioButton) to BUTTON_DOWN)
{
// button pressed, so toggle state
nvoSwitchState.state = !nvoSwitchState.state;
nvoSwitchState.value = nvoSwitchState.state ? 200 : 0;
}
when (reset) {
io_change_init(ioButton);
... // other reset processing
}
Explicit Propagation of Network Variables
As described earlier in this chapter, a network variable update is normally
initiated when a device assigns a value to an output network variable. In this
case, the network variable update is initiated implicitly by code that is generated
by the compiler to handle the variable’s modification.
An application can also explicitly request propagation for the output network
variable. Such explicit propagation is commonly used in the implementation of
“heartbeats,” regularly scheduled repeated propagation of the most recent value,
as supported by many interoperable devices. This technique could also be useful
in situations where the variable is not directly modifiable, or it might also result
from using pointers to network variables.
A device’s program can propagate any output network variables at any time,
including during initial power up and when transitioning from offline to online.
Network variable propagation on initial power-up can cause network congestion
if many devices are powered-up at the same time, and they all do power-up
propagation.
The application explicitly propagates an output network variable with the
propagate( ) function. The syntax is shown below:
propagate ([
network-var
network-var
If no network variable is specified, all output network variables for the device are
propagated. The
identifier, or an element of a network variable array, as in
network variable array name is used without an array index, all elements of the
array are propagated.
The propagate( ) function can be used to send the value of an output network
variable that is declared const, and thus cannot be assigned to. Because a value
assignment triggers implicit network variable propagation, and because a const
variable cannot be assigned to, an explicit mechanism for propagation is
required. See the propagate( ) function in the
additional information.
network-var
]);
Specifies an output network variable identifier.
identifier can also be a network variable array
nv_array[index
Neuron C Reference Guide
]. If a
for
60 How Devices Communicate Using Network Variables
Example:
network output SNVT_temp nvoTemp;
when (timer_expires(heartbeat))
{
propagate(nvoTemp);
}
The propagate( ) function can also be useful where pointers are used to update
output network variables. For example, assume that some function, f( ),
calculates a complicated set of values and places them in a network variable
structure. Assume the function is designed to operate on several similar such
variables within a device, thus the function is passed a pointer to each variable.
For efficiency, it might be best to code this function to operate on the variables
through a pointer reference. However, the Neuron C compiler cannot distinguish
between a pointer to a regular application variable, and a pointer to a network
variable. Thus, updates to a network variable through a pointer do not trigger an
implicit propagation, and an explicit propagation is required.
Furthermore, because of the inability to distinguish pointers to network
variables, Neuron C treats pointers to network variables as pointers to const
data, thus avoiding the problem of a modification to the variable through the
pointer. In Neuron C, removal of the const attribute is not normally permitted.
However, the #pragma relaxed_casting_on directive directs the compiler to
permit this cast. Casting can either be explicit, or implicit by variable
assignment or function parameter passing.
Example:
network output SNVT_temp_f nvoTemp;
//
// the hypothetical function f() could be supplied with a
// binary (pre-compiled) function library for easy re-use,
// of for protection of intellectual property (function
// f’s algorithm).
//
extern void f(SNVT_temp_f* pNv);
when (some-event)
{
#pragma relaxed_casting_on
// Without pragma above, this would result in
// an error, because the address of a network
// variable is treated as 'const <type> *'.
// Passing such a type as the function parameter
// results in an implicit cast, since the function
// prototype defines the variable as '<type> *'.
f((SNVT_temp_f*)&nvoTemp);
propagate(nvoTemp); // Explicit propagation needed
// because f() modified nvoTemp by pointer.
}
Neuron C Programmer’s Guide 61
Initial Value Updates for Input Network Variables
Many applications react not only to physical inputs received through I/O models
and peripheral hardware, but also respond to input network variable values. For
those devices, power-up (and post-reset) behavior must be carefully considered.
Example: A simple room temperature controller might accept a temperature
sensor’s current reading through an input network variable, and might compute
and output a control value that drives the valve:
When this device powers up, it simply waits for the current temperature input
value to change. After a new value is received, the device updates the
nvoValveDriver output network variable, and the valve moves to a new position.
For many devices, this model is sufficient. The temperature sensor’s reading
changes over time, and most sensors also implement periodic heartbeats at a
configurable interval. When the heartbeat interval expires, or the actual
temperature reading changes over the the threshold of a hysteresis, the sensor
updates its output network variable, the room temperature controller takes
appropriate action, and the heating valve is adjusted accordingly. The devices in
this network respond to external events and act as soon as necessary.
Some devices, however, need to produce up-to-date control values sooner after
power-up or reset, or need to ensure a consistent and up-to-date set of input
network variables. Consider, for example, an enhanced room temperature
controller. This new controller also accepts a temperature setpoint value through
an input network variable.
However, this example is flawed, because it cannot successfully compute a new
control value unless both input network variables have been updated. There are
several ways to solve this problem:
•Track the last-known good value using a suitable type of non-volatile
memory or a battery back-up device design.
Most low-cost non-volatile memory parts, such as EEPROM and flash
memory, have a limited number of write cycles. Therefore, this approach
only works with infrequently updated input network variables, and also
assumes that the actual setpoint and current temperature do not change
much compared to that last-known good value.
62 How Devices Communicate Using Network Variables
when(nv_update_occurs(nviCurrent)) {
received |= CURRENT_OK;
if (received & ALL_OK == ALL_OK) {
nvoValve = algorithm(lastGoodCurrent, lastGoodSetpoint);
}
}
when(nv_update_occurs(nviSetpoint)) {
received |= SETPOINT_OK;
if (received & ALL_OK == ALL_OK) {
nvoValve = algorithm(lastGoodCurrent, lastGoodSetpoint);
}
}
After power-up, poll both input network variables, thus explicitly
requesting that the data sources resend their most recent value. This
solution is popular, simple, and straight-forward.
While this straight-forward solution is adequate for many devices, it is not
without problems:
•The multi-NV polling approach still needs to ensure that all input
network variables have been updated prior to computing a new output
value. The last example also needs to track arrival of all input network
variable updates, as demonstrated in the previous example.
•Polling network variables immediately after reset (or power-up) can lead
to network congestion for a site-wide power-up, and can cause the
network stabilization to take some time after power has been applied.
While reset-time polling is not a problem if only a small number of devices issue
only a small number of poll requests, a single device (or its developer) does not
normally know the nature and application algorithm of the other devices in the
network.
When using power-up polls, combined with a suitable technique to monitor input
network variable updates, it is strongly recommended that you insert a random
delay of a few seconds between the reset and the initiation of these poll requests.
This delay helps to spread the power-up peak traffic demand in the network, and
improves overall startup performance.
The best option, where appropriate, is to use poll-free techniques. Tracking of
incoming updates, keeping records of last known-good-values or use of
heartbeating sensors are all good tools to solve the problem of initial network
variable updates for many devices.
64 How Devices Communicate Using Network Variables
Monitoring Network Variables
A monitoring device is a LONWORKS device that receives data from many other
devices. For example, an alarm display device may monitor many alarm sensor
devices. The sensor devices could all have a network variable output declared as
a SNVT_alarm output, and the monitor device could have a network variable
input, declared as a SNVT_alarm input.
Typically, the monitor device waits for a change to its input network variable.
When a change occurs, it must identify which device originated the change. The
method of determining the source of a change depends on the method used to
connect the sensor outputs to the monitor input.
Following are a few options for the network monitor device; in the examples, the
sensor devices all have a single SNVT_alarm output network variable that must
be monitored by the network monitor device:
•Declare the network variable input as an array, and connect each
element of the array to a different sensor. Wait for an nv_update_occurs
event for the entire array, and then use the nv_array_index built-in
variable to determine which device originated the change.
Example:
network input SNVT_alarm nviAlarmArray[50];
SNVT_alarm alarm_value;
unsigned int alarm_device;
when (nv_update_occurs(nviAlarmArray))
{
alarm_device = nv_array_index;
alarm_value = nviAlarmArray[alarm_device];
// Process alarm_device and alarm_value
}
This method is appropriate when the number of devices to be monitored
does not exceed the network variable limits of the monitoring device.
•Declare the network variable input as a single input on the monitor
device, and declare the network variable outputs as polled outputs on the
sensor devices. Create a single connection with all the sensor outputs
and the monitor input. Explicitly poll each of the sensors using explicit
addressing and explicit messages as described in the next chapter.
Because the devices are explicitly polled, the monitor device always
knows the source of a network variable update.
This method is appropriate for any number of devices, as long as the
delays introduced by the polling loop are acceptable for the application.
•Declare the network variable input as a single input and create a single
connection with all the sensor outputs sending their values to the single
monitor input. This configuration is called a
an nv_update_occurs event for the network variable input, and then use
the nv_in_addr built-in variable to determine the source address of the
device that originated the change. Implement a configuration property
array that is set by the device plug-in to identify the fanned-in devices.
Neuron C Programmer’s Guide 65
fan-in connection
. Wait for
Following is an example for the code on a network monitor device:
when (nv_update_occurs(nviAlarm)) {
alarm_device_addr = nv_in_addr;
alarm_value = nviAlarm;
// Process alarm_device_addr and alarm_value
// Look up alarm_device_addr in a configuration
// property set by a plug-in at installation time
}
This method is appropriate for any number of devices.
Neuron C Reference Guide
The
variable.
describes the contents of the nv_in_addr built-in
Authentication
Authentication is a special form of an acknowledged service between one writer
device and from 1 to 63 reader devices. Authentication is used by the reader
devices to verify the identity of the writer device. This type of service is useful,
for example, if a device containing an electronic lock receives a message to open
the lock. By using authentication, the electronic lock device can verify that the
“open” message comes from the owner, not from someone attempting to break
into the system.
Authentication doubles the number of messages per transaction. Authentication
can be used with acknowledged updates or network variable polls. It cannot be
used with unacknowledged or repeated updates. An acknowledged message
normally requires two messages, an update and an acknowledgment. An
authenticated message requires four messages, as shown in
This could affect system response time and capacity.
The following sections describe how to set up devices to use authentication and
how authentication works.
Setting Up Devices to Use Authentication
Figure 8 on page 68.
To set up a device to use authenticated network variables or send authenticated
messages, follow these steps:
1 Declare the network variable as authenticated. For application messages
to be authenticated, specify TRUE in the authenticated field of the
msg_out object.
2 Specify the authentication key to be used for this device using a network
tool. The LonMaker tool can be used to install a key during development.
These steps are described in more detail in the following sections.
66 How Devices Communicate Using Network Variables
Declaring Authenticated Variables and
Messages
For network variables, include the authenticated (or auth) keyword as part of the
connection information. The partial syntax is shown below. For complete syntax
of the bind-info clause, see the
Note: The authenticated keyword can be abbreviated as auth. Likewise, the
nonauthenticated keyword can be abbreviated as nonauth.
If you also include the config keyword in the declaration, network tools can
change the authentication status of this network variable after the device has
been installed. Include the nonconfig keyword to prevent the authentication
status from being changed for this network variable.
With this declaration, authentication can never be turned off for updates of the
nvoSafeLock network variable, because the declaration includes the nonconfig
keyword.
Neuron C Reference Guide
.
Specifying the Authentication Key
All devices that read or write a given authenticated network variable connection
must have the same authentication key. This 48-bit authentication key is used
in a special way for authentication, as described below.
The key itself is transmitted to the device only during the initial configuration.
All subsequent changes to the key do not involve sending it over the network.
The network tool can modify a device’s key over the network, in a secure fashion,
with a network management message.
How Authentication Works
The following sequence describes an example of authentication (Figure 8 on page
68 illustrates the process):
1 Device A sends an update to a network variable declared as
authenticated on Device B using the acknowledged service. If Device A
does not receive the challenge, it sends a retry of the initial update.
2 Device B generates a 64-bit random number and returns, to Device A, a
challenge packet that includes the 64-bit random number. Device B then
uses the encryption algorithm (built into the Neuron firmware) to
compute a transformation on that random number using its 48-bit
authentication key and the message data. The transformation is stored
in Device B.
3 Device A then also uses the encryption algorithm (built in to the Neuron
firmware) to compute a transformation on the random number (returned
to it by Device B) using its 48-bit authentication key and the message
data. Device A then sends this computed transformation to Device B.
Neuron C Programmer’s Guide 67
4 Device B compares its computed transformation with the number it
receives from Device A. If the two numbers match, the identity of the
sender is verified, and Device B can perform the requested action and
send its acknowledgment to Device A. If the two numbers do not match,
Device B does not perform the requested action and an error is logged in
the error table.
If the acknowledgment is lost and Device A tries to send the same message again,
Device B remembers that the authentication was successfully completed, and
acknowledges it again.
ACKD Message or
1
Request
Device A
(Writer)
Challenge
2
Reply to challenge
3
4
ACK or Response
Figure 8. Authentication Process
Device B
(reader)
If Device A attempts to update an output network variable connected to multiple
readers, each receiver device generates a different 64-bit random number and
sends it in a challenge packet to Device A. Device A must then transform each of
these numbers and send a reply to each receiver device.
The principal strength of authentication is that it cannot be defeated by simple
record and playback of commands that implement the desired functions (for
example, unlocking the lock). Authentication does not require that the specific
messages and commands be secret, because they are sent unencrypted over the
network, and anyone who is determined can read those messages.
It is good practice to connect a device directly to a network tool with no other
devices on the same network when installing its authentication key the first
time. This prevents the key from being sent over a large network where an
intruder might detect it. Once a device has its authentication key, a network tool
can modify the key, over the network, by sending an increment to be added to the
existing key.
Alternatively, your development tool might support exporting your device’s
application image in a pre-configured state including your initial authentication
key. See your development tool’s documentation for information about exporting
pre-configured application images.
Changeable-Type Network Variables
You can create network variables that support their type and size being changed
during installation. This kind of network variable is called a
network variable
.
changeable-type
68 How Devices Communicate Using Network Variables
You can use a changeable-type network variable to implement a generic
functional block that works with different types of inputs and outputs. For
example, you can create a general-purpose device that can be used with a variety
of sensors or actuators, and then create a functional block that allows the
integrator to select the network variable type depending on the physical sensor or
actuator attached to the device during installation.
You can support type changing to any network variable type defined in a resource
file (that is, any SNVT or UNVT in a resource file). You can only create a
changeable-type network variable if the network variable is a member of a
functional block, and if it is not a configuration network variable. An integrator
typically uses a plug-in that you create to change network variable types. A
network variable cannot change its type or size while it is connected (because the
change would make the connection invalid).
The NodeBuilder Code Wizard generates code that contains a framework for
supporting changeable-type network variables; see
Network Variable
The following details all that is required to create a changeable-type network
variable without the use of the NodeBuilder Code Wizard, followed by a detailed
discussion of the requirements that the application must meet to support the
changeable-type network variables. The section completes with a commented
source code example.
in the
NodeBuilder User’s Guide
Using a Changeable-Type
for details.
To create a changeable-type network variable, follow these steps:
1 Implement the network variable with the changeable_type keyword.
This keyword results in information being provided in the device
interface description. This information specifies that the variable’s
implementation permits the type of the network variable to be changed
by a network tool. You must declare an initial type for the network
variable, and the size of the initial type must be equal to the largest
network variable size that your application supports.
For example, the following declaration declares a changeable-type output
network variable, with an initial type of SNVT_volt_f. This type is a 4byte floating-point value, so this network variable can support changes to
any network variable type of 4 or fewer bytes.
2 Set the changeable-interface bit in the program ID for the device
template. You can set this bit by setting Has Changeable Interface in the
standard program ID calculator when you create the device template, as
described in the
3 Implement a SCPTnvType configuration property that applies to the
changeable-type network variable. See Chapter 4,
NodeBuilder User’s Guide
Properties to Configure Device Behavior
information about configuration properties. This configuration property
is used by network tools to notify your application of changes to the
network variable type.
.
Using Configuration
, on page 83, for more
Your application requires notification of changes to this configuration
property. You can provide this notification by declaring the configuration
property with the reset_required or object_disabled modifier and checking
the SCPTnvType value in the director function, or you can implement
Neuron C Programmer’s Guide 69
configuration property access through LW-FTP and check, in the
stop_transfer( ) function, whether the SCPTnvType value has been
modified. Alternatively, you can implement the SCPTnvType
configuration property as a configuration network variable and check the
current type in the task for the nv_update_occurs(
For example, the following code declares a changeable-type output
network variable with its SCPTnvType configuration property.
4 You can optionally declare a SCPTmaxNVLength configuration property
that applies to the changeable-type network variable. This configuration
property can be used to inform network tools of the maximum type length
supported by the changeable-type network variable. This value is a
constant, so declare this configuration property with the const modifier.
For example, the following code adds a SCPTmaxNVLength configuration
property to the example in the previous step.
5 Implement code in your Neuron C application to process changes to the
SCPTnvType value. The required code is described in the following
section.
Implement code to provide information about the current length of the
network variable to the Neuron firmware. This is described in
a Size Change
Implement your application’s algorithm such that it can process all
possible types the changeable-type network variable might use at
runtime. An example and fragment for such code is shown in
Changeable-Type Example
6 The LonMaker browser provides your integrators with a user interface to
change network variable types. You typically want a custom interface for
integrators to change network variable types on your device. For
example, the custom interface could restrict the available types to the
types supported by your application, thus preventing configuration
errors. To provide a custom interface, implement code in your plug-in to
provide an interface for users to change the network variable type. The
required plug-in code is discussed in the
.
Guide
You cannot change the type of a configuration property unless it inherits its type
from a changeable-type network variable. In this case, the configuration
on page 74.
on page 75.
LNS Plug-in Programmer’s
Processing
70 How Devices Communicate Using Network Variables
property automatically assumes the size and type of the network variable it
applies to, and is governed by the same initial type and maximum size.
Processing Changes to a SCPTnvType CP
When a plug-in or the LonMaker browser changes the type of a network variable,
it informs your application of the change by writing a new value to the
SCPTnvType configuration property associated with the network variable. The
definition of the SCPTnvType type is provided below:
typedef struct {
unsigned short type_program_ID[8];
unsigned short type_scope;
unsigned long type_index;
nv_type_category_t type_category;
unsigned short type_length;
signed long scaling_factor_a;
signed long scaling_factor_b;
signed long scaling_factor_c;
} SCPTnvType;
By default, a SCPTnvType configuration property is initialized to the following
values:
• Program ID = {0, 0, 0, 0, 0, 0, 0, 0}
• Scope = 0
• Index = 1
• Category = NVT_CAT_INITIAL (see
72)
• Type length = 1 byte
• Scaling factor A = 0
• Scaling factor B = 0
• Scaling factor C = 0
Important: Because LNS sets network-variable values through the SCPTnvType
configuration property, your application must initialize the SCPTnvType
configuration property to a meaningful value for the application. This initialized
value also becomes the “last-known good value” for the application, in case a
type-change request must be rejected (see
When your application detects a change to the SCPTnvType value, it must
determine if the change is valid, as described in
72. If it is valid, the application must process the change, as described in
page
Processing a Type Change
determines that the change is not valid or supported, it must report an error, as
described in
supported by your application, and the change also changes the size of the
network variable, your application must implement the size change, as described
Processing a Size Change
in
Rejecting a Type Change
on page 73. On the other hand, if the application
on page 75. If the change is valid and
on page 74.
Validating a Type Change
Rejecting a Type Change
Validating a Type Change
on page
on page 75).
on
Neuron C Programmer’s Guide 71
Validating a Type Change
There are several ways that your application can determine if it supports a
particular SCPTnvType value. It can look for specific types, as specified by the
type_program_ID, type_scope, and type_index fields. Alternatively, it can look
for specific type categories, as defined by the type_category and type_length
fields.
The type_program_ID and type_scope values specify a program ID template and
a resource scope that together uniquely identify a resource file set. The
type_index value identifies the network variable type within that resource file
set. If the type_scope value is 0, the type_index value is a SNVT index. The
type_program_ID, type_scope, and type_index values uniquely identify a type to
your application as well as to any network tools that need to determine the
current type, or modify the type, of the network variable to which the property
applies. Your application can ignore these values if the remaining fields in the
SCPTnvType structure provide sufficient information for the application.
The type_category enumeration is defined in the <snvt_nvt.h> include file as
follows:
This enumeration describes the type, stating whether it is a signed short, or
floating-point, or structure, for example, but not providing information about
structure or union fields or other similar details. The type_length field is
necessary to provide the number of bytes of a structure or union type, though it is
set for all types. To support all scalar types, test for a type_category value
between NVT_CAT_SIGNED_CHAR and NVT_UNSIGNED_LONG, plus
NVT_CAT_SIGNED_QUAD. To also support floating point types, also test for a
type_category value of NVT_FLOAT.
The SCPTnvType configuration property can be shared between multiple
changeable-type network variables. In this case, the application must make sure
to process all network variables from the property’s application set —
SCTPnvType applies to all these network variables, and so does the type change
request. The type change can only be accepted if all related network variables can
perform the required change.
72 How Devices Communicate Using Network Variables
(
(
)
If one or more type-inheriting configuration properties apply to changing
configuration network variables (CPNVs), these type-inheriting CPNVs also
change their type at the same time. If this type-inheriting CPNV is shared among
multiple network variables, all related network variables must change to the new
type. Sharing a type-inheriting configuration property among both changeable
and non-changeable network variables is not supported.
Processing a Type Change
When the application detects a type change request and recognizes the type
detailed in the related SCPTnvType property as a supported type, and also
confirms that all affected network variables can perform the change, the
application performs the type change.
To perform a type change that does not change the size of the network variable,
your application need do nothing but memorize the current type details. A
different part of the application, the type-independent implementation of your
application’s algorithm, queries these details as and when required, and
processes the network variable data accordingly. The processing required in the
type-independent implementation of the application depends on the range of
types supported by your application. For example, if your application only
supports changing between different floating-point types, no additional
processing might be required. If your application supports changing between
different scalar types, it might require the use of scaling factors and network
variable type length to convert the raw network variable value to a scaled value.
For example, the SNVT_lev_cont type is an unsigned short value that represents
percentages from 0 to 100 percent, with a resolution of 0.5%. The actual data
raw
values (also called
scaling factors for SNVT_lev_cont are defined as a=5, b= -1, c=0. To convert from
raw data to scaled fixed-point data, use the following formula:
values) are in the variable range from 0 to 200. The
b
)
crawascaled
+=*10*
Your application can convert the raw data of a changeable type input network
variable, internally, to an actual scaled value for use as a floating-point data
item, for example, using the above formula. To convert the data back to a raw
value for an output network variable, use the following inverted scaling formula:
scaled
raw
You can use cast operations and pointer manipulations to handle type changes.
Changeable-Type Example
See
If a network variable type or size is changed and that network variable is a
member of an inheriting configuration property’s application set, and that
property is implemented as a configuration network variable, then the
application must process the same type or length changes that were performed on
the network variable for the configuration network variable.
However, if the configuration property is implemented within a configuration file,
no change to the configuration file is required. The configuration file states the
configuration property’s initial and maximum size (in the CP documentationstring
inheriting CPs from the associated network variable.
Neuron C Programmer’s Guide 73
⎛
=
⎜
⎝
length
a
⎞
c
−
⎟
b
10*
⎠
on page 75 for an example.
field), and LNS derives the current and actual type for type-
Your application must always support the NVT_CAT_INITIAL type category. If
the requested type is of that category, your application must ignore all other
content of the SCPTnvType configuration property and change the related
network variable’s type back to its initial type. The network variable’s initial
type is the type the network variable was declared with in Neuron C
(SNVT_volt_f in the earlier example).
Processing a Size Change
If a supported change to the SCPTnvType configuration property results in a
change in the size of a network variable type, your application must provide code
to memorize the current length of the network variable. It must further provide
code to inform the Neuron firmware about the current length of the changeabletype network variable. The current length information must be kept in nonvolatile storage, but details of the required implementation depend on the chosen
mechanism for supporting the Neuron firmware.
Two such mechanisms are supported, a legacy one called the
a more robust
You can explicitly set and maintain the new length of the network variable using
the built-in nv_len property of the network variable. You can access and modify
the built-in nv_len property as shown below:
Important: When the Neuron C compiler detects use of the nv_len property to
modify a network variable's length, it requests that the linker place the network
variable fixed configuration table in writeable memory. This could make it
difficult to fit such an application into the memory of a device based on a Neuron
3150 Chip or an FT 3150 Smart Transceiver if the device has no writeable
external memory for the application, such as EEPROM or flash memory.
Starting with version 14, the Neuron firmware implements an
override system image extension
the firmware needs the length of a network variable, it calls the
get_nv_length_override( ) system image extension to get it. Compared to writing
to the nv_len property, this new method provides more reliable updates to
network variable sizes, because the old method could cause a device to go
applicationless if a power failure occurred in the middle of a network variable
size update.
NV length override system image extension
that is managed by the application. Whenever
nv_len method
method.
NV length
, and
You can enable the NV length override system image extension
following compiler directive:
74 How Devices Communicate Using Network Variables
with the
The get_nv_length_override( ) function returns the current length of the network
variable with the index specified in the argument, or 0xFF to indicate that the
type has not been changed and the network variable’s initial length is still valid.
The system image extension method only works with version 14 firmware, or
newer. To support development of applications that use the best possible method
depending on the target hardware, you can use conditional compilation to
support both methods. This is, for example, used by the NodeBuilder Code
Wizard to allow for the LTM-10A device to exercise and implement support for
changeable-type network variables. The changeable-type example, later in this
chapter, implements such a strategy.
Whenever possible, the system image extension technique should be used,
because of its more robust implementation. However, a compiler directive is
provided to permit the use of the system_image_extensions nv_length_override
directive with targets that do not support system extensions. You can turn the
NLD#477 linker error, which would normally occur in such a condition, into a
linker warning by using the following directive:
If a network tool attempts to change the type of a changeable-type network
variable to a type that is not supported by the application, your application must
do the following:
•Report the error within a maximum of 30 seconds from the receipt of the
type change request. To report the error, the application should signal an
invalid_request through the Node Object functional block and optionally
disable the related functional block. If the application does not include a
Node Object functional block, the application can set an applicationspecific error code using the error_log( ) function and take the device
offline (use go_offline( )).
By setting the functional block status, the rest of the functional blocks on
your device can continue to function normally. You can use both methods
to provide a more precise indication of the error to a network integrator.
5,
See Chapter
on page
• Reset the SCPTnvType value to the last known good value.
• Reset all other housekeeping data, if any, so that the last known good
type is re-established.
In the interest of future-proof implementations, the application should be sure to
reject all change requests to unknown types, as shown in the changeable-type
example below.
101, for more information on using functional blocks.
Using Functional Blocks to Implement a Device Interface
,
Changeable-Type Example
The following code sample shows a typical implementation of a changeable-type
network variable. It implements nvoVolt as a changeable-type output network
variable. This example uses utility functions, such as getObjStatus( ),
updateNode_Status( ), and setFblockDisable( ). These utility functions are part
Neuron C Programmer’s Guide 75
of the framework provided by NodeBuilder Code Wizard. Your application might
not contain those functions, and you should consider providing equivalent
functionality in that case.
Parts of the example below are shown in boldface type. This indicates the most
important parts of the example. The rest of the code (non-boldface type) can be
considered more detail-oriented on first read-through.
// Forward-declaration of the fblock’s director function:
void fbSensorDirector(unsigned uFbIndex, int iCommand);
// Declare the SCPTnvType family. Note the use of the
// cp_info modifier; the application must have some
// mechanism to become aware of a type change request
// so that it can validate and honor or reject that
// request. Other possibilities for such a notification
// include the object_disable or offline CP flags, or
// the implementation of this CP as a configuration
// network variable.
// SCPTmaxNVLength is optional, but allows for a
// network tool to filter out those types that will
// not be acceptable due to excessive length. The
// type change routine, below, still must verify that
// the requested type is within supported limits.
const SCPTmaxNVLength cp_family nvMaxLength;
// Declare the changeable-type network variable.
// The network variable's initial type also determines
// its maximum length, hence the initialization of the
// nvMaxLength property using the sizeof() operator
// applies to the NV's inital type.
// nvTypeLastGood memorizes the last known good type of the
// changeable-type network variable. This is not a
// configuration property, but a simple (EEPROM) variable
// using the same type.
// Note this variable must be initialized correctly, to
// allow the device to come out of the initial reset cycle
// without an accidental type change, and to allow the
// changeable-type NV to function correctly even without
// an explicit type change:
// The following two compiler directives enable the system extension,
76 How Devices Communicate Using Network Variables
// and allow for its use even if the target device doesn't support
// system extensions. See text for details, and see the Neuron C
// Reference Guide, Compiler Directives, for details about these
// directives.
#pragma system_image_extensions nv_length_override
#pragma unknown_system_image_extension_isa_warning // see text!
// changeLength() performs or rejects the type change request.
// It is called from the director function in response to a
// device reset because the SCPTnvType has been declared with
// "cp_info(reset_required)." Other CP flags, such as
// object_disabled, require a different invocation. SCPTnvType
// may also be implemented as a configuration network variable,
// allowing for invocation of the changeLength() function from
// a "when(nv_update_occurs(...))" task.
void changeLength(void) {
// First, check to see if there is anything to do at all:
// is there a real type change request pending? The
// changeLength() function could have been invoked as a
// result of a regular device reset (or whichever other
// update notification event is associated with the nvType CP).
if ((nvoVolt::nvType.type_category != NVT_CAT_NUL)
// In case multiple network variables share the same
// SCPTnvType configuration property, make sure all
// affected network variables are unbound. Use is_bound()
// for all these network variables and reject the type change
// if any reports being bound.
// Check if requested type is within acceptable size
// limits. The sizeof(nvoVolt) function always returns the
// initial size of the network variable, which equals
// its maximum size.
if (nvoVolt::nvType.type_length > sizeof(nvoVolt)) {
// Reject: set the nvType CP back to the last known
// good value, log the error, and notify the
// network tool. In addition to the minimum
// requirements, this example implementation
// also automatically disables the fblock
case NVT_CAT_SIGNED_LONG:
case NVT_CAT_UNSIGNED_LONG:
case NVT_CAT_FLOAT:
// Accept long and float.
// Store the current type information and, for
// debugging purpose only, also change the length of
// the network variable via its nv_len property. See
// further below for an example implementation of the
// recommended get_nv_length_override technique for
// this network variable.
nvTypeLastGood = nvoVolt::nvType;
#ifdef _DEBUG // see text!
nvoVolt::nv_len = nvoVolt::nvType.type_length;
Neuron C Programmer’s Guide 77
#endif
// For all inheriting configuration properties that
// apply to this network variable and that are
// implemented as configuration network variables,
// repeat this type change.
break;
case NVT_CAT_INITIAL:
// This is a request to change the type back to its
// initial type (whichever is the initial type).
// For cardinal types with significant scaling
// factors A, B, or C, the application may need to
// restore those scaling factors or to preserve
// that knowledge otherwise; see GetCurrent() or
// SetCurrent() functions, below, for details.
// The sizeof() function always returns the size of
// the initial type.
#ifdef _DEBUG // see text!
nvoVolt::nv_len = nvoVolt::nvType.type_length;
#endif
// For all inheriting configuration properties that
// apply to this network variable and that are
// implemented as configuration network variables,
// repeat this type change.
break;
// Reject all other types. This example implementation
// just refuses the change request and continues to
// operate on the last known good type:
default:
nvoVolt::nvType = nvTypeLastGood;
error_log(TYPE_ERROR);
getObjStatus(fbSensor::global_index)->invalid_request
= TRUE;
updateNode_Status();
} // end of switch
} // any change at all
} // function changeLength()
// The fbSensorDirector() function manages this functional block.
// Because the nvType CP has been declared with the reset_required
// flag, the director must call the changeLength() function as part
// of the reset processing to allow for the type change request to
// be executed.
// The director function is not called automatically, but
// requires a framework that explicitly calls the director.
// The director implementation shown here is incomplete, as it
// ignores all other commands and duties. See the director
// implementation generated by the NodeBuilder Code Wizard
// for a more comprehensive example of a director function, and
// for a complete framework that issues director invocations.
void fbSensorDirector(unsigned uFbIndex, int iCommand) {
if ((TFblock_command)iCommand == FBC_WHEN_RESET) {
changeLength();
setLockedOutBit(uFbIndex, FALSE);
} // FBC_WHEN_RESET
} // fbSensorDirector()
// Whenever the current length of the changeable network-type variable is
// required by the Neuron firmware, the firmware calls the
// get_nv_length_override() system image extension. This function
78 How Devices Communicate Using Network Variables
// returns the current length of the given NV (in bytes) or 0xFF to
// indicate that the initial type is still unchanged.
if (uNvIndex == fbSensor::nvoValue::global_index) {
// Return current length for our example NV, or return
// 0xFF to indicate the NV has the initial length:
if (nvTypeLastGood.type_category != NVT_CAT_INITIAL
&& nvTypeLastGood.type_category != NVT_CAT_NUL) {
// this is a distinct current length:
uResult = nvTypeLastGood.type_length;
}
}
return uResult;
}
// Triggered by some appropriate I/O event, timer, or network event,
// the application will need to process data for the changeable-type
// network variable. This example does not include an algorithm that
// performs numeric operations using the changeable-type data, but two
// conversion routines are shown that convert the current type of
// the changeable network variable into a float_type variable for
// internal use in such numeric operations, and vice versa.
void GetCurrent(float_type* const pFloat) {
// One union to hold all possible current types, plus the initial
// type of the changeable type NV
union {
unsigned long uLong;
signed long sLong;
SNVT_volt_f xInitial;
} nvLocal;
// bProcessABC: a flag to indicate whether the scaling factors
// A,B,C must be honored and used
boolean bProcessABC;
bProcessABC = FALSE;
nvLocal.xInitial = nvoVolt;
switch (nvoVolt::nvType.type_category) {
case NVT_CAT_SIGNED_LONG:
// Current type is signed long. Convert to float.
fl_from_slong(nvLocal.sLong,pFloat);
bProcessABC = TRUE;
break;
case NVT_CAT_UNSIGNED_LONG:
// Current type is unsigned long. Convert to float.
fl_from_ulong(nvLocal.uLong,pFloat);
bProcessABC = TRUE;
break;
case NVT_CAT_INITIAL:
// Fall through to float.
case NVT_CAT_FLOAT:
// Float is current. No conversion is required, just
// copy data into local variable.
*pFloat = nvLocal.xInitial;
break;
default:
// Unsupported type. The changeLength() handler should
// have recognized this and rejected the type earlier.
// Log this application error and set the device offline:
error_log(TYPE_ERROR);
go_offline();
} // switch
if (bProcessABC) {
Neuron C Programmer’s Guide 79
// TODO: If needed by the application algorithm, transform
// the raw *pFloat NV value into the scaled float equivalent
// using the following formula:
// scaled = A * 10**B * (*pFloat + C)
// Scaling factors are accessible via the scaling_factor_X
// members of the SCPTnvType CP, for example
// nvo1::nvType.scaling_factor_a. This transformation is a
// costly operation and it is recommended to design
// the application algorithm such that this conversion
// is not required at all, if possible.
// TODO: if needed by the application algorithm, revert the
// conversion done in GetCurrent() by using the following
// formula:
// raw = (*pFloat / (A * 10**B)) - C
// See GetCurrent(), above, for more details.
}
switch (nvoVolt::nvType.type_category) {
case NVT_CAT_SIGNED_LONG:
// Current type is signed long. Convert from float.
nvLocal.sLong = fl_to_slong(pFloat);
break;
case NVT_CAT_UNSIGNED_LONG:
// Current type is unsigned long. Convert from float.
nvLocal.uLong = fl_to_ulong(pFloat);
break;
case NVT_CAT_INITIAL:
// Fall through to float.
case NVT_CAT_FLOAT:
// Float is current. No conversion is required, just
// copy data into local variable.
nvLocal.xInitial = *pFloat;
break;
default:
// Unsupported type. The changeLength() handler should
// have recognized this and rejected the type earlier.
// Log this application error and set the device offline:
// Update the actual network variable in case the conversion
// was OK (current type is in fact supported).
// A more generic implementation of these conversion functions
// is likely to use a pointer to the changeable type network
// variable's initial type as a second argument, thus allowing
// the SetCurrent() and GetCurrent() functions to be used for
// all changeable type NVs of the same initial type.
// This approach is likely to require explicit calls to the
// propagate() function; see the Neuron C Reference Guide
80 How Devices Communicate Using Network Variables
This chapter discusses the declaration and use of
configuration properties. Configuration properties are part
of the device interface, and are used by network tools to
configure device behavior during and after network
installation.
Neuron C Programmer’s Guide 83
Overview
A configuration property is a data item that, like a network variable, is part of
the device’s interoperable interface. A configuration property can be modified by
a network tool. Configuration properties facilitate interoperable installation and
configuration tools by providing a standardized network interface for device
configuration data. Like network variables, configuration properties also provide
a well-defined interface.
Each configuration property type is defined in a resource file that specifies the
data encoding, scaling, units, default value, invalid value, range, and behavior for
configuration properties based on the type. A rich variety of standard
configuration property types (SCPTs) are defined in the standard resource file
set. You can view all currently defined SCPTs online at
can also create your own user configuration property types (UCPTs) that are
defined in resource files that you create with the NodeBuilder Resource Editor.
Declaring Configuration Properties
You can implement a configuration property using one of two different
techniques. The first, called a
variable to implement the configuration property. This method has the
advantage of enabling the configuration property to be modified by another
ONWORKS device, just like any other network variable. It also has the
L
advantage of having the Neuron C event mechanism available to provide
notification of updates to the configuration property.
configuration network variable
types.lonmark.org. You
, uses a network
The disadvantages of configuration network variables are that they are limited to
a maximum of 31 bytes each, and that the number of configuration network
variables is determined by the maximum number of network variables for the
target platform.
To implement a configuration property as a configuration network variable,
declare it using the network … config_prop syntax described in
Configuration Network Variables
The second method of implementing configuration properties uses
to implement the configuration properties for a device. Rather than being
files
separate externally exposed data items, all configuration properties implemented
within configuration files are combined into one or two blocks of data called
. A value file consists of configuration property records of varying length
files
concatenated together. Each value file must fit as contiguous bytes into the
memory space in the device that is accessible by the application. When there are
two value files, one contains writeable configuration properties and the second
contains read-only data. To permit a network tool to access the data items in the
value file, there is also a
the elements in the value files.
The advantages of implementing configuration properties as configuration files is
that there are no limits on configuration property size or the number of
configuration properties, except as constrained by the available memory space on
the device. The disadvantages are that other devices cannot connect to or poll a
configuration property implemented as a configuration file, instead requiring a
network tool to modify a configuration property implemented within a
template file
on page 85.
, an array of text characters that describes
Declaration of
configuration
value
84 Using Configuration Properties to Configure Device Behavior
configuration file, and no events are automatically generated when a
configuration property implemented within a configuration file is updated. The
application can force notification of updates by requiring network tools to reset
the device, disable the functional block, or take the device offline when a
configuration property is updated (though the reset or online notification is the
only type of notification that occurs after the configuration property has been
modified). Alternatively, the application can also force notification by
implementing configuration file access through the L
protocol (LW-FTP) and monitoring the stop_transfer( ) function. This option
requires additional code space for the LW-FTP server code.
To implement a configuration property as a part of a configuration file, declare it
with the cp_family syntax described in
on page 86.
Files
Declaring Configuration Properties within
ONWORKS file transfer
Declaration of Configuration Network Variables
The configuration network variable declaration syntax is similar to the
declaration syntax of a non-configuration network variable as already discussed
3,
in Chapter
The complete syntax for declaring a configuration network variable is shown
below. The declaration is made distinct from other network variable declarations
by the inclusion of the config_prop keyword following the type of the network
variable declaration. The config_prop keyword can be abbreviated as cp.
The
the previous chapter, and they apply equally to a configuration network variable
as they do to any other network variable, except that the
A config network variable is not a fully managed configuration property, it is a
manually managed one. The config keyword is obsolete and not recommended for
use in new development, but is provided to allow legacy applications to be used
with the Neuron C Version 2 compiler.
Similar to the configuration CP family members, configuration network variables
must be declared with a
within a resource file. The type can be a standard (SCPT) or user (UCPT) type.
cp-modifiers
The
identical with the CP family declaration discussed earlier in this chapter (see the
clause that can optionally follow the config_prop keyword is also
for a discussion of the
] [
class] type
] [
class] type
portions of this syntax were discussed in depth in
config_prop [cp-
[ =
initial-value
config_prop [cp-
class
cp-modifiers
modifiers
] ;
modifiers
] [ =
initializer-list
cannot be config.
syntax and
]
]
] ;
The
connection-info
connection info for any other input network variable, as discussed in the previous
chapter. Like any other network variable, a configuration network variable can
be an array, with each element of the array being a separately handled
Neuron C Programmer’s Guide 85
for a configuration network variable is no different than the
configuration property, or with the entire configuration network variable array
being handled as a single configuration property. See
Configuration Properties
on page 88 for details.
Instantiation of
A configuration network variable's declaration can contain an
initializer-list
previous chapter.
variable cannot, itself, also have a network variable property list. That is, you
cannot define configuration properties that apply to other configuration
properties.
When using a network variable array as a configuration property or properties,
particular care should be given to the compiler's rules of initialization for that
network variable array. The array elements can be initialized in the declaration,
as is the case with any variable or array variable declaration. If some or all of
the array elements are not initialized, the uninitialized elements default to a zero
initialization. However, each array element can be initialized when it appears as
a property in a properties clause, and this declaration overrides the initialization
in the declaration, but only for the element that appears in that property clause.
Similarly, if the entire network variable array is used as a single configuration
property, the entire array can be initialized when it appears as a property in a
properties clause.
You cannot change the type of a configuration property unless it inherits its type
from a changeable-type network variable.
, like any other network variable declaration, as discussed in the
Unlike
any other network variable, a configuration network
initial-value
Declaring Configuration Properties within Files
You can declare a configuration property that is to be implemented within a
configuration file using a CP family declaration. A CP family declaration can be
meta
thought of as a
program. It can be used to declare a collection of many configuration properties,
identical in type and certain other settings, but individually applying to one or
more different network variables, functional blocks (as described in Chapter
Using Functional Blocks to Implement a Device Interface
device itself. A CP family can have zero members, one member, or many
members. No code or data is generated until you declare members of the CP
family, as described later. In this regard, the CP family is similar to a C
language typedef.
-declaration, defining a type construct for later use in the
, on page 101), or the
or an
5,
The syntax for declaring a CP family is shown below:
for a CP family cannot be just a standard C type, such as int or char.
Instead, the declaration must use a configuration property type (CPT) from a
resource file. The configuration property type can either be a standard
configuration property type (SCPT) or a user configuration property type (UCPT).
There are over 300 SCPT definitions available today, and you can create your
own manufacturer-specific types using UCPTs. The SCPT definitions are stored
86 Using Configuration Properties to Configure Device Behavior
in the standard.typ file, which is part of the standard resource file set included
with the NodeBuilder tool. There can be many similar resource files containing
UCPT definitions, and these are managed by the NodeBuilder Resource Editor as
described in the
A configuration property type is similar to an ANSI C typedef, but it is also much
more. The configuration property type also defines standardized semantics for
the type. The configuration property definition in a resource file contains
information about the default value, minimum and maximum valid values, a
designated (optional) invalid value, and language string references that permit
localized descriptive information, additional comments, and units strings to be
associated with the configuration property type.
NodeBuilder User’s Guide
.
cp-modifiers
The
of option keywords. The keywords and their meanings are discussed in the
Configuration Property and Network Variable Declarations
Neuron C Reference Guide
If the declaration of the CP family contains an
the family identifier name, each member of the CP family is declared to be a
separate array. For example, a family can consist of three members: an array
property for some network variable
network variable
The
not provided in the declaration, the default value specified by the resource file is
used. The
but the compiler replicates the initial value for each instantiated family member.
The initialization rules for a CP family member are shown below. The
initialization rules are used to set the initial value that is to be loaded in the
value file from the linked image, as well as the value file stored in the device
interface file. A network tool can use the initial value as a
might, at times, reset the configuration properties (or a subset of them) back to
the default values. Consult the documentation of the particular network tool, for
example, the
configuration property default values.
begin with the cp_info keyword followed by a parenthesized list
chapter of the
.
array-bound
A
, another array property for another
B
, and a third array property for a functional block C.
in the declaration of a CP family is optional. If
initial-value
given is an initial value for a single member of the family,
expression following
initial-value
default value
LonMaker User's Guide
, for more information on the tool’s use of
is
, and
In the initialization rules that follow, the compiler uses the first rule that applies
to the configuration property.
1 If the configuration property is initialized explicitly in its instantiation,
then this is the initial value that is used.
2 If the configuration property is initialized explicitly in the CP family
declaration, then the family initializer is used.
3 If the configuration property applies to a functional block, and the
functional profile that defines the functional block specifies a default
value for the associated configuration property member, then the
functional profile default is used.
Neuron C Programmer’s Guide 87
4 If the configuration property type for the configuration property defines a
default value, then that default value is used as the initial value. This
rule does not apply for a configuration property type that is typeinheriting; see
5 If no initial value is available from any of the preceding rules, a value of
all zeros is used.
The cp_family declaration is repeatable. The declaration can be repeated two or
more times, and, as long as the duplicated declarations match in every regard,
the compiler treats them as a single declaration.
The following example shows a valid repetition, two invalid repetitions, and a
non-repeating case.
// NO REPETITION, but creation of a valid second family:
SCPTgain cp_family cp_info(offline) cpLowGain = { 1, 8 };
Type-Inheriting Configuration Properties
on page 98.
Instantiation of Configuration Properties
Configuration properties can apply to a device, one or more functional blocks, or
one or more network variables. In each case, a configuration property is made to
apply to its respective objects through a
device and network variables are explained in the following sections; property
lists for functional blocks are explained in Chapter
Implement a Device Interface
configuration property of any given SCPT or UCPT type that applies to an object,
where that object is a network variable, a functional block, or the entire device.
As discussed above, the cp_family declaration is similar to a C language typedef
because no actual variables are created as a result of the declaration. In the case
of a type definition, variables are instantiated when the type definition is used in
a later declaration that is not, itself, another typedef. At that time, variables are
instantiated
for and assigned to the variables. The variables can then be used in later
expressions in the executable code of the program.
The instantiation of a CP family member occurs each time the CP family
declaration’s identifier is used in a property list. For exceptions to this rule, see
, which means that variables are declared and memory is allocated
, on page 101. You cannot have more than one
Sharing of Configuration Properties
However, a configuration network variable is already instantiated at the time it
is declared. For a configuration network variable, the property list serves only to
property list
on page 96.
. Property lists for the
5,
Using Functional Blocks to
88 Using Configuration Properties to Configure Device Behavior
Loading...
+ hidden pages
You need points to download manuals.
1 point = 1 manual.
You can buy points or you can get point for every manual you upload.