Echelon Neuron C User Manual

Neuron
®
C Programmer’s Guide
®
0 7 8 - 0 0 0 2 -02H
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.
Printed in the United States of America. Copyright © 1990, 2009 Echelon Corporation.
Echelon Corporation
www.echelon.com

Welcome

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
(078­0392-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 }
netvar modifier, class
, and
bind-info
are all optional
Neuron C Programmer’s Guide v
Table of Contents
Welcome.........................................................................................................iii
Audience ........................................................................................................iii
Related Documentation ................................................................................iv
Typographic Conventions for Syntax...........................................................iv
Chapter 1. Overview .......................................................................................... 1
What Is Neuron C?......................................................................................... 2
Comparing Neuron C Version 2 to Version 1 ........................................ 2
Unique Aspects of Neuron C .........................................................................3
Neuron C Integer Constants................................................................... 4
Neuron C Variables ................................................................................. 5
Neuron C Variable Types .................................................................5
Neuron C Storage Classes ................................................................ 6
Variable Initialization ......................................................................7
Neuron C Declarations .....................................................................7
Network Variables, SNVTs, and UNVTs............................................... 8
Configuration Properties......................................................................... 9
Functional Blocks and Functional Profiles.......................................... 10
Data-Driven Compared with Command-Driven Protocols........... 11
Event-Driven Scheduling or Polled Scheduling .................................. 11
Low-Level Messaging ............................................................................11
I/O Devices ............................................................................................. 11
Neuron-Hosted and Host-Based Compilation ............................................ 12
Differences between Neuron C and ANSI C............................................... 13
Chapter 2. Focusing on a Single Device.......................................................... 15
What Happens on a Single Device? ............................................................ 16
The Scheduler............................................................................................... 16
When Clauses ........................................................................................16
When Statement .................................................................................... 17
Types of Events Used in When Clauses............................................... 18
Predefined Events ................................................................................. 18
Event Processing............................................................................. 20
Reset Event ..................................................................................... 21
User-Defined Events .............................................................................22
Scheduling of When Clauses................................................................. 22
Priority When Clauses ..........................................................................23
Interrupts............................................................................................... 24
Function Prototypes ..............................................................................24
Timers ........................................................................................................... 25
Declaring Timers ................................................................................... 25
Examples .........................................................................................26
The timer_expires Event....................................................................... 26
Input/Output ................................................................................................27
I/O Object Types ....................................................................................28
Declaring I/O Objects in Neuron C....................................................... 29
Device Self-Documentation .........................................................................30
Examples ......................................................................................................30
Example 1: Thermostat Interface........................................................ 31
Example 2: Simple Light Dimmer Interface....................................... 33
Example 3: Seven-Segment LED Display Interface........................... 35
Input Clock Frequency and Timer Accuracy.............................................. 36
Neuron C Programmer’s Guide vii
Fixed Timers .......................................................................................... 36
Scaled Timers and I/O Objects ............................................................. 37
Calculating Accuracy for Software Timers .......................................... 37
Accuracy of Millisecond Timers ..................................................... 37
Accuracy of Second Timers............................................................. 40
Delay Functions..................................................................................... 40
EEPROM Write Timer .......................................................................... 41
Chapter 3. How Devices Communicate Using Network Variables ................ 43
Major Topics ................................................................................................. 44
Overview ....................................................................................................... 45
Behavior of Writer and Reader Devices ............................................... 46
When Updates Occur............................................................................. 47
Declaring Network Variables ...................................................................... 47
Examples of Network Variable Declarations....................................... 48
Connecting Network Variables ................................................................... 49
Use of the is_bound( ) Function ............................................................ 50
Network Variable Events ............................................................................51
The nv_update_occurs Event ................................................................ 51
The nv_update_succeeds and nv_update_fails Events ....................... 52
The nv_update_completes Event .......................................................... 53
Synchronous Network Variables................................................................. 53
Declaring Synchronous Network Variables......................................... 54
Synchronous vs. Nonsynchronous Network Variables........................ 54
Updating Synchronous Network Variables .........................................54
Preemption Mode ............................................................................ 55
Processing Completion Events for Network Variables.............................. 55
Partial Completion Event Testing........................................................ 55
Comprehensive Completion Event Testing ......................................... 55
Tradeoffs................................................................................................. 56
Polling Network Variables .......................................................................... 56
Declaring an Input Network Variable as Polled .................................58
Declaring an Output Network Variable as Polled............................... 58
Explicit Propagation of Network Variables................................................ 60
Initial Value Updates for Input Network Variables.................................. 62
Monitoring Network Variables.................................................................... 65
Authentication.............................................................................................. 66
Setting Up Devices to Use Authentication .......................................... 66
Declaring Authenticated Variables and Messages ....................... 67
Specifying the Authentication Key ................................................ 67
How Authentication Works................................................................... 67
Changeable-Type Network Variables ......................................................... 68
Processing Changes to a SCPTnvType CP .......................................... 71
Validating a Type Change .............................................................. 72
Processing a Type Change.............................................................. 73
Processing a Size Change ...............................................................74
Rejecting a Type Change ................................................................75
Changeable-Type Example ...................................................................75
Chapter 4. Using CPs to Configure Device Behavior ..................................... 83
Overview ....................................................................................................... 84
Declaring Configuration Properties............................................................ 84
Declaration of Configuration Network Variables................................ 85
Declaring Configuration Properties within Files ................................ 86
viii
Instantiation of Configuration Properties .................................................. 88
Device Property Lists ............................................................................ 89
Network Variable Property Lists ......................................................... 90
Accessing Property Values from a Program............................................... 91
Advanced Configuration Property Features .............................................. 92
Configuration Properties Applying to Arrays...................................... 92
Initialization of Configuration Properties at Instantiation ................ 95
Sharing of Configuration Properties .................................................... 96
Configuration Property Sharing Rules ................................................97
Type-Inheriting Configuration Properties ........................................... 98
Type-Inheriting CPs for NVs of Changeable Type........................ 99
Chapter 5. Using Functional Blocks to Implement a Device Interface.........101
Overview ..................................................................................................... 102
Functional Block Declarations ..................................................................104
Functional Block Property Lists......................................................... 107
Shared Functional Block Properties .................................................. 108
Scope Rules................................................................................................. 109
Accessing Members and Properties of an FB from a Program................ 110
Accessing Members and Properties of an FB from a Network Tool .......112
The Director Function................................................................................ 113
Sharing of Configuration Properties......................................................... 115
Chapter 6. How Devices Communicate Using Application Messages...........117
Introduction to Application Messages ......................................................118
Layers of Neuron Software........................................................................ 119
Implicit Messages: Network Variables .................................................... 119
Application Messages................................................................................. 120
Constructing a Message............................................................................. 120
The msg_out Object Definition ........................................................... 121
Message Tags ................................................................................122
Message Codes .............................................................................. 123
Block Transfers of Data ...................................................................... 124
Sending a Message..................................................................................... 125
Receiving a Message ..................................................................................126
The msg_arrives Event ....................................................................... 126
The msg_receive( ) Function ............................................................... 127
Format of an Incoming Message......................................................... 127
Importance of a Default When Clause ............................................... 128
Application Message Examples................................................................. 129
Lamp Program ..................................................................................... 129
Switch Program ................................................................................... 129
Connecting Message Tags ................................................................... 130
Explicit Addressing.................................................................................... 130
Sending a Message with the Acknowledged Service ............................... 131
Message Completion Events ...............................................................131
Processing Completion Events for Messages ..............................133
Preemption Mode and Messages............................................................... 134
Asynchronous and Direct Event Processing............................................. 135
Using the Request/Response Mechanism ................................................. 136
Constructing a Response.....................................................................137
Sending a Response............................................................................. 138
Receiving a Response ..........................................................................138
The resp_arrives Event................................................................. 138
Neuron C Programmer’s Guide ix
The resp_receive( ) Function ........................................................ 139
Format of a Response.................................................................... 139
Request/Response Examples............................................................... 140
Comparison of resp_arrives and msg_succeeds ................................. 141
Idempotent Versus Non-Idempotent Requests.................................. 141
Application Buffers ....................................................................................142
Allocating Application Buffers............................................................ 143
Chapter 7. Additional Features......................................................................145
The Scheduler............................................................................................. 146
Scheduler Reset Mechanism ..................................................................... 146
Scheduler Example..............................................................................148
Bypass Mode............................................................................................... 149
The post_events( ) Function................................................................ 149
Watchdog Timer ......................................................................................... 150
Additional Predefined Events ...................................................................151
Going Offline in Bypass Mode ............................................................152
Wink Event ..........................................................................................152
Interrupts ...................................................................................................153
Interrupt Sources ................................................................................ 153
I/O Interrupts ................................................................................ 154
Timer/Counter Interrupts ............................................................ 154
Periodic System Timer Interrupts ............................................... 154
Defining an Interrupt Task ................................................................ 155
Defining an I/O Interrupt Task.................................................... 155
Defining a Timer/Counter Interrupt Task ..................................156
Defining a System Timer Interrupt Task.................................... 158
Controlling Interrupts.........................................................................159
Sharing Data with an Interrupt Task................................................ 161
Interrupt Latency ................................................................................162
Debugging Interrupt Tasks................................................................. 164
Restrictions for Using Interrupts ....................................................... 165
Sleep Mode.................................................................................................. 165
Flushing the Neuron Chip or Smart Transceiver ............................. 166
The flush( ) and flush_cancel( ) Functions ..................................166
flush_completes Event .................................................................. 166
Putting the Device to Sleep................................................................. 166
Forced Sleep......................................................................................... 168
Error Handling........................................................................................... 168
Resetting the Device............................................................................ 169
Restarting the Application.................................................................. 169
Taking an Application Offline ............................................................170
Disabling a Functional Block.............................................................. 170
Changing Functional Block Status..................................................... 171
Logging Application Errors.................................................................171
System Errors ......................................................................................171
Access to Device Status and Statistics .....................................................172
Chapter 8. Memory Management...................................................................173
Memory Use................................................................................................ 174
RAM Use .............................................................................................. 174
EEPROM Use ......................................................................................174
Using Neuron Chip Memory .....................................................................176
Chips with Off-Chip Memory.............................................................. 176
x
Chips without Off-Chip Memory ........................................................ 177
Memory Regions ..................................................................................177
Memory Areas...................................................................................... 178
Default Memory Usage ....................................................................... 180
Controlling Non-Default Memory Usage ........................................... 181
eeprom Keyword (for Functions and Data Declarations) ........... 181
far Keyword (for Data Declarations) ........................................... 182
offchip Keyword (for Functions and Data Declarations) ............183
onchip Keyword (for Functions and Data Declarations) ............183
ram Keyword (for Functions) .......................................................183
uninit Keyword (for Data Declarations) ......................................184
Compiler Directives ............................................................................. 184
When the Program Is Relinked ..........................................................184
Use of Flash Memory........................................................................... 184
Use of Flash Memory for Series 3100 Chips ............................... 185
Use of Flash Memory for Series 5000 Chips ............................... 186
The eeprom_memcpy( ) Function .......................................................187
Reallocating On-Chip EEPROM ............................................................... 188
Address Table ......................................................................................188
Alias Table ...........................................................................................189
Domain Table....................................................................................... 190
Allocating Buffers ...................................................................................... 190
Buffer Size............................................................................................ 191
Application Buffer Size................................................................. 191
Network Buffer Size...................................................................... 192
Errors............................................................................................. 192
Buffer Counts.......................................................................................192
Compiler Directives for Buffer Allocation.......................................... 193
Outgoing Application Buffers....................................................... 194
Outgoing Network Buffers ...........................................................194
Incoming Network Buffers ...........................................................195
Incoming Application Buffers....................................................... 195
Number of Receive Transactions ................................................. 195
Usage Tip for Memory-Mapped I/O ..........................................................198
What to Try When a Program Does Not Fit on a Neuron Chip .............. 199
Reduce the Size of the Configuration Property Template File ......... 200
Reduce the Number of Address Table Entries .................................. 200
Remove Self-Identification Data if Not Needed ................................ 200
Remove Network Variable Names if Not Needed ............................. 201
Declare Constant Data Properly ........................................................ 201
Use Efficient Constant Values............................................................ 202
Take Advantage of Neuron Firmware Default Initialization ...........202
Use Neuron C Utility Functions Effectively ...................................... 202
Be Aware of Library Usage................................................................. 203
Use More Efficient Data Types........................................................... 203
Observe Declaration Order ................................................................. 204
Use the Optional fastaccess Feature.................................................. 205
Eliminate Common Sub-Expressions................................................. 205
Use Function Calls Liberally ..............................................................206
Use the Alternate Initialization Sequence......................................... 207
Use C Operators Effectively................................................................ 207
Use Neuron C Extensions Effectively ................................................208
Using the Link Map ................................................................................... 209
Neuron C Programmer’s Guide xi
Appendix A.
Neuron C Tools Stand-Alone Use..............................................211
Stand-Alone Tools ...................................................................................... 212
Common Stand-Alone Tool Use .......................................................... 212
Common Syntax ............................................................................212
Common Set of Basic Commands ................................................ 214
Command Switches for Stand-alone Tools ............................................... 215
Neuron C Compiler.............................................................................. 215
Neuron Assembler ............................................................................... 216
Neuron Linker .....................................................................................216
Neuron Exporter.................................................................................. 217
Neuron Librarian................................................................................. 219
Appendix B. Neuron C Function Libraries ....................................................221
Definitions ..................................................................................................222
NodeBuilder Support for Libraries ........................................................... 222
Tradeoffs, Advantages, and Disadvantages ............................................. 223
Advantages of a Library...................................................................... 223
Disadvantages of a Library................................................................. 223
Library Construction Using the Librarian............................................... 224
Performing Neuron C Functions from Libraries...................................... 225
Appendix C. Neuron C Custom System Images ............................................227
Definitions ..................................................................................................228
NodeBuilder Use of Custom System Images............................................ 229
Tradeoffs, Advantages, and Disadvantages ............................................. 230
Advantages of a Custom System Image............................................. 230
Disadvantages of a Custom System Image........................................ 230
Constructing a Custom System Image ..................................................... 231
Providing a Large RAM Space ..................................................................234
Performing Neuron C Functions ............................................................... 234
Appendix D. Neuron C Language Implementation Characteristics .............237
Neuron C Language Implementation Characteristics ............................ 238
Translation (J.3.1) ............................................................................... 238
Environment (J.3.2)............................................................................. 239
Identifiers (J.3.3) .................................................................................239
Identifiers (F.3.3 of ANSI C Standard)........................................ 239
Characters (J.3.4) ................................................................................240
Characters (F.3.4 of ANSI C Standard)....................................... 240
Integers (J.3.5)..................................................................................... 241
Integers (F.3.5 of ANSI C Standard) ...........................................241
Floating Point (J.3.6)........................................................................... 242
Arrays and Pointers (J.3.7) ................................................................. 242
Arrays and Pointers (F.3.7 of ANSI C Standard) .......................242
Hints (J.3.8) .........................................................................................243
Structures, Unions, Enumerations, and Bit-Fields (J.3.9) ............... 243
Structures, Unions, Enumerations, and Bit-Fields (F.3.9) ........ 243
Qualifiers (J.3.10) ................................................................................244
Declarators (F.3.11 of ANSI C Standard)....................................244
Statements (F.3.12 of ANSI C Standard) .................................... 244
Preprocessing Directives (J.3.11) ....................................................... 244
Library Functions (J.3.12) ..................................................................245
Index................................................................................................................247
xii
1

Overview

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 event­driven 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 free­standing 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 self­documentation 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 self­documentation 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 plug­in 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 event­driven 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 off­chip 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.
Table 2. ANSI C and Neuron C Declarations
Declaration Example
Simple data items int a, b, c;
Neuron C Programmer’s Guide 7
Declaration Example
Data types typedef unsigned long ULONG;
Enumerations enum hue {RED, GREEN, BLUE};
Pointers char *p;
Functions int f(int a, int b);
Arrays int a[4];
Structures and unions struct s {
int field1; unsigned field2 : 3; unsigned field3 : 4; };
In addition, Neuron C Version 2 supports the declarations listed in Table 3.
Table 3. Neuron C Version 2 Declarations
Declaration Example
I/O Objects IO_0 output oneshot relay_trigger;
(See Chapter 2)
Timers mtimer led_on_timer;
(See Chapter 2)
Network Variables network input SNVT_temp temperature;
(See Chapter 3)
Configuration Properties
Functional Blocks fblock SFPTnodeObject { … } myNode;
Message Tags msg_tag command;
cp_family SCPTdefOutput defaultOut;
(See Chapter 4)
(See Chapter 5)
(See Chapter 6)

Network Variables, SNVTs, and UNVTs

A
network variable
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 well­defined 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
LonMark Application Layer Interoperability Guidelines
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-of­messages/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 Command­Driven 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 self­identification 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 self­identification 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.
Network variable structures cannot contain pointers. Configuration
property structures also cannot contain pointers.
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 “implementation­specific” 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:
stimer repeating led_timer; when (some-event) { time_remaining = led_timer; ... }
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 self­documentation (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 pulse­width 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
//////////////// I/O Objects ////////////////////// IO_6 input ontime clock (1) invert ioTempRaw; IO_4 input quadrature ioShaftIn; IO_2 output bit ioHeatingOn = FALSE; IO_3 output bit ioCoolingOn = FALSE;
//////////////// 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
when (reset) { tmCheckHeatOrCool = 300; // 5 minutes, repeating }

Example 2: Simple Light Dimmer Interface

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
/////////////////////// I/O Objects //////////////////// IO_0 output triac pulse sync (IO_6) clock (6) ioLampTriac; IO_4 input quadrature ioShaftIn;
//////////////////////// 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;
/////////////////////////// Tasks //////////////////////
// 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:
IO_2 output bit ioEnable = 1; IO_8 neurowire master select(IO_2) ioDisplay; unsigned char displayReg[3]; unsigned char configReg; . . . void refreshDisplay() { __lock { io_out(ioDisplay, &configReg, 8); io_out(ioDisplay, displayReg, 24); } }
Neuron C Programmer’s Guide 35
Neuron Chip
IO_8 IO_9
IO_2
+5V
C4
.01
F
3 11 12 18 10
8
14
470
R10
U3
MC14489
Vdd CLOCK DATA IN DATA OUT
~ENABLE RX Vss
Multi-Character
LED Display Driver
BANK 1 BANK 2 BANK 3 BANK 4 BANK 5
7
A
6
B
5
C
4
D
2
E
1
F
20
G
19
H
9 13 15 16 17
Figure 4. Neurowire Connection to a Display
3 Digit LED Display
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
Table 7. Connecting Output Network Variables
Output (device/variable_name) Input (device/variable_name)
switch1/nvoSwitch lamp1/nviLamp
switch2/nvoSwitch lamp3/ nviLamp
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
network input SNVT_temp nviTemp; network output SNVT_switch nvoHeater; network output int nvoCurrentTemp;
Examples of priority network variable declarations are shown below:
network output SNVT_alarm bind_info(priority) nvoFireAlarm; network input boolean bind_info (priority(nonconfig)) nviFireAlarm;
An example of declaring a network variable using the unacknowledged service is the following:
network output SNVT_lev_cont bind_info(unackd) nvoFillLevel;
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:
nv_update_completes [( nv_update_fails [( nv_update_occurs [( nv_update_succeeds [(
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:
network input SNVT_temp nviSetpoint; network output SNVT_switch nvoHeater; network output SNVT_temp nvoCurrentTemp; when (nv_update_occurs(nviSetpoint)) { nvoHeater.state = nvoCurrentTemp < nviSetpoint; }
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:
boolean heater_failed; network output SNVT_switch nvoHeater; when (nv_update_fails(nvoHeater)) { heater_failed = TRUE; // remember update failure }
when (nv_update_succeeds(nvoHeater)) {
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.)
// ensure multiple alarms are handled serially network output sync SNVT_alarm nvoAlarm;
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
///////////////// Network Variables //////////////////// network input SNVT_switch nviLampState;
//////////////////////// Constants ///////////////////// #define LED_ON 0 #define LED_OFF 1
/////////////////////// 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.
Listing 1. Lamp Program Using Polling
// LAMP.NC -- Sample lamp actuator program, // polls the switch periodically
///////////////////// Network Variables //////////////// network input SNVT_switch nviLampState;
//////////////////////// Constants ///////////////////// #define LED_ON 0 #define LED_OFF 1
/////////////////////// I/O Objects //////////////////// IO_0 output bit ioLED = LED_OFF;
//////////////////////// Timers //////////////////////// mtimer tmPoll;
/////////////////////////// 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
//////////////////// Network Variables //////////////// network output polled SNVT_switch nvoSwitchState;
//////////////////////// Constants //////////////////// #define BUTTON_DOWN 0 #define BUTTON_UP 1
/////////////////////// I/O Objects ////////////////////
Neuron C Programmer’s Guide 59
IO_4 input bit ioButton = BUTTON_UP;
/////////////////////////// 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:
network input SNVT_temp nviCurrent; network output SNVT_volt nvoValve;
when(nv_update_occurs(nviCurrent)) { nvoValve = control_algorithm(nviCurrent); }
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.
Example:
network input SNVT_temp nviCurrent; network input SNVT_temp nviSetpoint; network output SNVT_volt nvoValve;
when(nv_update_occurs(nviSetpoint)) when(nv_update_occurs(nviCurrent)) { nvoValve = control_algorithm(nviCurrent, nviSetpoint); }
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
Example:
network input SNVT_temp nviCurrent; network input SNVT_temp nviSetpoint; network output SNVT_volt nvoValve;
eeprom uninit SNVT_temp lastGoodCurrent, lastGoodSetpoint;
when(nv_update_occurs(nviCurrent)) { lastGoodCurrent = nviCurrent; nvoValve = algorithm(lastGoodCurrent, lastGoodSetpoint); }
when(nv_update_occurs(nviSetpoint)) { lastGoodSetpoint = nviSetpoint; nvoValve = algorithm(lastGoodCurrent, lastGoodSetpoint); }
After power-up or reset, track which network variable has been updated,
and execute the algorithm only after all required input data has arrived.
Example:
#define CURRENT_OK 0x01 #define SETPOINT_OK 0x02 #define ALL_OK (CURRENT_OK | SETPOINT_OK)
unsigned received;
network input SNVT_temp nviCurrent; network input SNVT_temp nviSetpoint; network output SNVT_volt nvoValve;
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.
Example:
network input SNVT_temp nviCurrent; network input SNVT_temp nviSetpoint; network output SNVT_volt nvoValve;
when(reset) { poll(nviCurrent);
Neuron C Programmer’s Guide 63
poll(nviSetpoint); } when(nv_update_occurs(nviSetpoint)) when(nv_update_occurs(nviCurrent)) { nvoValve = control_algorithm(nviCurrent, nviSetpoint); }
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.
Example:
network input SNVT_temp nviCurrent; network input SNVT_temp nviSetpoint; network output SNVT_volt nvoValve;
mtimer powerupDelay;
when(reset) { powerupDelay = 16ul * random() + 500ul; // 0.500 to 4.5s delay }
when(timer_expires(powerupDelay)) { poll(nviCurrent); poll(nviSetpoint); } when(nv_update_occurs(nviSetpoint)) when(nv_update_occurs(nviCurrent)) { nvoValve = control_algorithm(nviCurrent, nviSetpoint); }
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:
Example:
network input SNVT_alarm nviAlarm; SNVT_alarm alarm_value; nv_in_addr_t alarm_device_addr;
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
bind_info ( authenticated [(config | nonconfig)] )
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.
Example:
network output UNVT_boolean bind_info(auth(nonconfig)) nvoSafeLock;
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 4­byte floating-point value, so this network variable can support changes to any network variable type of 4 or fewer bytes.
network output changeable_type SNVT_volt_f nvoValue;
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.
Example:
SCPTnvType cp_family cp_info(reset_required) nvType;
network output changeable_type SNVT_volt_f nvoValue nv_properties { nvType };
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.
Example:
SCPTnvType cp_family cp_info(reset_required) nvType; const SCPTmaxNVLength cp_family nvMaxLength;
network output changeable_type SNVT_volt_f nvoValue nv_properties { nvType, nvMaxLength=sizeof(SNVT_volt_f) };
cpnv-name
) event.
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:
typedef enum nv_type_category_t { /* 0 */ NVT_CAT_INITIAL = 0, // Initial (default) type /* 1 */ NVT_CAT_SIGNED_CHAR, // Signed Char /* 2 */ NVT_CAT_UNSIGNED_CHAR, // Unsigned Char /* 3 */ NVT_CAT_SIGNED_SHORT, // 8-bit Signed Short /* 4 */ NVT_CAT_UNSIGNED_SHORT, // 8-bit Unsigned Short /* 5 */ NVT_CAT_SIGNED_LONG, // 16-bit Signed Long /* 6 */ NVT_CAT_UNSIGNED_LONG, // 16-bit Unsigned Long /* 7 */ NVT_CAT_ENUM, // Enumeration /* 8 */ NVT_CAT_ARRAY, // Array /* 9 */ NVT_CAT_STRUCT, // Structure /* 10 */ NVT_CAT_UNION, // Union /* 11 */ NVT_CAT_BITFIELD, // Bitfield /* 12 */ NVT_CAT_FLOAT, // 32-bit Floating Point /* 13 */ NVT_CAT_SIGNED_QUAD, // 32-bit Signed Quad /* 14 */ NVT_CAT_REFERENCE, // Reference /* -1 */ NVT_CAT_NUL = -1 // Invalid Value } nv_type_category_t;
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 documentation­string 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 changeable­type network variable. The current length information must be kept in non­volatile 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:
Example of legacy nv_len property:
size_t oldNVLen, newNVLen; oldNVLen = nv-name::nv_len; nv-name::nv_len = newNVLen;
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:
#pragma system_image_extensions nv_length_override
Using this compiler directive with a version of the Neuron firmware that does not support system extensions causes an NLD#477 linker error.
To implement a NV length override system image extension, provide a function with the following prototype:
unsigned get_nv_length_override(unsigned uNvIndex);
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:
#pragma unknown_system_image_extension_isa_warning
Rejecting a Type Change
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 application­specific 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.
#include <control.h> #include <float.h> #include <mem.h> #include <snvt_nvt.h>
#pragma relaxed_casting_on #define TYPE_ERROR 1 #define NV_LENGTH_MISMATCH 2
// 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.
SCPTnvType cp_family cp_info(reset_required) nvType;
// 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.
network output changeable_type SNVT_volt_f nvoVolt nv_properties { nvType, nvMaxLength=sizeof(SNVT_volt_f) };
// A functional block that contains // the changeable-type network variable:
fblock SFPTopenLoopSensor { nvoVolt implements nvoValue; director fbSensorDirector; } fbSensor external_name("Sensor");
// 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:
eeprom SCPTnvType nvTypeLastGood = {{0, 0, 0, 0, 0, 0, 0, 0}, 0, 1, NVT_CAT_INITIAL, 1, 0, 0, 0};
// 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)
&& (memcmp((void*)&nvTypeLastGood,(void*)&nvoVolt::nvType, sizeof(SCPTnvType)) != 0)) {
// 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
nvoVolt::nvType = nvTypeLastGood; error_log(TYPE_ERROR); getObjStatus(fbSensor::global_index)->invalid_request = TRUE; updateNode_Status(); setFblockDisable(fbSensor::global_index, TRUE);
} else switch (nvoVolt::nvType.type_category) {
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.
nvoVolt::nvType.type_length = sizeof(nvoVolt); nvTypeLastGood = nvoVolt::nvType;
#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.
unsigned get_nv_length_override(unsigned uNvIndex) { unsigned uResult; uResult = 0xFF;
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.
} } // GetCurrent() void SetCurrent(float_type* pFloat) {
// One union to hold all possible current types, plus the initial // type of the changeable NV.
union { unsigned long uLong; signed long sLong; SNVT_volt_f xInitial; } nvLocal;
boolean bConversionOK; boolean bProcessABC;
bConversionOK = TRUE; bProcessABC = nvoVolt::nvType.type_category == NVT_CAT_SIGNED_LONG || nvoVolt::nvType.type_category == NVT_CAT_UNSIGNED_LONG;
if (bProcessABC) {
// 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:
error_log(TYPE_ERROR); go_offline(); bConversionOK = FALSE; } // switch
if (bConversionOK) {
// 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
// for details.
nvoVolt = nvLocal.xInitial; } // bConversionOK } // SetCurrent()
Neuron C Programmer’s Guide 81
Using Configuration Properties to
4
Configure Device Behavior
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.
How Devices Communicate Using Network Variables
, on page 43.
network input [ [
network input [ [
Examples:
network input SCPTupdateRate config_prop nciUpdateRate;
network input SCPTbypassTime cp nciBypassTime = ...
netvar-modifier
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
Neuron C Reference Guide
semantics).
netvar-modifier connection-info] identifier
netvar-modifier connection-info] identifier [array-bound
and
class
type
that is defined by a configuration property type
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:
type
[const]
cp_family [cp-
modifiers] family-ident
[=
initial-value
] ;
family-ident : identifier [ array-bound ] identifier
Example:
SCPTgain cp_family cpGain = { 2, 3 };
The
type
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
Example:
SCPTgain cp_family cpGain[3] = { { 2, 3 }, { 1, 5 }, { 2, 1 } };
initial-value
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 type­inheriting; 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.
Example:
// INITIAL declaration of family: SCPTgain cp_family cpGain = { 2, 3 };
// VALID repetition: families are identical SCPTgain cp_family cpGain = { 2, 3 };
// INVALID repetition: different initializer! SCPTgain cp_family cpGain = { 1, 10 };
// INVALID repetition: different cp_info SCPTgain cp_family cp_info(offline) cpGain = { 2, 3 };
// 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...