REFERENCE GUIDE SNAP® Network Operating System User Manual for Version 2.5 ©2008-2015 Synapse, All Rights Reserved. All Synapse products are patent pending. Synapse, the Synapse logo, SNAP, and Portal are all registered trademarks of Synapse Wireless, Inc. Doc# 600025-01B 6723 Odyssey Drive // Huntsville, AL 35806 // (877) 982-7888 // Synapse-Wireless.
Disclaimers Information contained in this Manual is provided in connection with Synapse products and services and is intended solely to assist its customers. Synapse reserves the right to make changes at any time and without notice. Synapse assumes no liability whatsoever for the contents of this Manual or the redistribution as permitted by the foregoing Limited License.
Table of Contents 1. Introduction ............................................................................................................... 1 SNAP and SNAPpy ............................................................................................................................ 1 Portal and SNAP Connect 3.x ........................................................................................................... 1 The SNAP Wireless Sniffer..........................................................
Transparent Data (Wireless Serial Port) ........................................................................................ 21 Scripted Serial I/O (SNAPpy STDIO) ............................................................................................... 21 The Switchboard ............................................................................................................................ 21 Loopback .............................................................................................
Scripts specific to the RF100 Platform..................................................................................... 52 Scripts specific to the RF200 Platform..................................................................................... 53 Scripts specific to the RF266 Platform..................................................................................... 53 Scripts specific to the RF300/RF301 Platform .........................................................................
1. Introduction SNAP and SNAPpy The Synapse SNAP product line provides an extremely powerful and flexible platform for developing and deploying embedded wireless applications. The SNAP network operating system is the protocol spoken by all Synapse wireless nodes. The term SNAP has also evolved over time to refer generically to the entire product line. For example, we often speak of “SNAP Networks,” “SNAP Nodes,” and “SNAP Applications.” SNAP core software runs on each SNAP node.
Each of these guides walks you through the basics of unpacking your evaluation kit, setting up your wireless nodes, and installing Portal software on your PC. You may find it helpful to start with one of these manuals, even if you are not starting with an EK2500 or EK2100 kit. (Synapse SNAP nodes are also sold separately, as well as bundled into evaluation kits.) About This Manual This manual assumes you have read and understood the SNAP Primer and either the “EK2100 Users Guide” or the “EK2500 Users Guide.
Every Portal and SNAP Firmware release comes with a release notes document describing what has changed since the previous release. All of these documents are in Portable Document Format (PDF) files for download from the Synapse website. SNAP Documentation by Category The table below may help you navigate the SNAP Documentation. It categorizes the existing documentation set across two dimensions. Horizontally we categorize the various manuals as “Introductory” or “Reference”.
2. SNAP Overview SNAP is a family of software technologies that together form an integrated, end-to-end solution for wireless monitoring and control. The latest version is 2.5, which this document covers. Key features of SNAP • • • • • All devices are peers – any device can be a bridge for Portal, do mesh routing, sleep, etc. There are no “coordinators” in SNAP. SNAP implements a full mesh topology.
Figure 1 - Example HVAC System Showing RPC Call-flow (arrows) RPCs are a fundamental part of SNAP’s communication infrastructure, enough so that there is an entire section of this manual devoted to it, beginning on page 32. SNAPpy Scripting SNAPpy is a subset of the Python programming language, optimized for low-power embedded devices. A SNAPpy “script” is a collection of functions and data that is processed by Portal and uploaded to SNAP devices.
You won’t have to search long to find an immense amount of information regarding Python on the Web. Besides your favorite search engine, a good place to start looking for further information is Python’s home site: http://python.org/ The Documentation page on Python’s home site contains links to tutorials at various levels of programming experience, from beginner to expert. As mentioned earlier, Portal acts as a peer in the SNAP network, and can send and receive RPC calls like any other node.
3. SNAPpy – The Language SNAPpy is basically a subset of Python, with a few extensions to better support embedded real-time programming. Here is a quick overview of the SNAPpy language.
x123 = 99 # OK 123x = 99 # not OK Identifiers may only contain alphanumeric characters and underscores x123_percent = 99 x123% = 99 $%^ = 99 # OK # not OK # not OK There are several types of variables a = True # Boolean b = False c = 123 # Boolean # Integer, range is -32768 to 32767 d = "hello" # String, size limits vary by platform e = (1, 2, 3) f = None # Tuple – usable only as a constant in SNAPpy # Python has a "None" data type g = startup # Function In the above example, invoking g() w
def displayStatus(msg1, msg2): print msg1 + msg2 …but in your SNAPpy scripts you have RPC calls like… rpc(PORTAL_ADDR, "displayStatus", 1, 2, 3) # <- too many parameters provided …or… rpc(PORTAL_ADDR, "displayStatus", 1) # <- too few parameters provided …then you are going to see no output at all in Portal. Because the “signatures” do not match, Portal does not invoke the displayStatus() function at all.
def changeGlobal(): global x # because of this statement… x = 314 # ...
The usual math operators are supported Symbol Meaning + Addition - Subtraction * Multiplication / Division % Modulo (remainder function) y = m*x + b z = 5 % 4 # z is now 1 result = 14 / 8 # result is now 1 -- integer math only SNAPpy does not support floating point, only integers. SNAPpy integers are 16-bit signed values ranging from -32768 to 32767. If you add 1 to 32767, you will get 32768. SNAPpy does not generate an error if you divide by zero. The result of that division will be zero.
Variables do have types, but they can change on the fly x = 99 # variable x is currently an integer (int) x = False x = "hello" # variable x is now a Boolean value of False # variable x is now a string (str) x = (x == "hello") # variable x is now a Boolean value of True Functions can change, too If you have two function definitions that define functions with the same name, even with different parameter signatures, only the second function will be available.
4. SNAPpy versus Python Here are more details about SNAPpy, with emphasis on the differences between SNAPpy and Python. Modules SNAPpy supports import of user-defined as well as standard predefined Python source library modules. from module import * from module import myFunction import module # Supported # Supported # Not supported Variables Local and Global variables are supported. On RAM-constrained devices, SNAPpy images are typically limited to 64 system globals and 64 concurrent locals.
SNAPpy currently does not support the following common Python types, so they cannot be used in SNAPpy scripts. They can still be used in Python scripts running in Portal or a SNAP Connect application. • • • • • • • float – A float is a floating-point number, with a decimal part. long – A long is an integer with arbitrary length (potentially exceeding the range of an int). complex – A complex is a number with an imaginary component. list – A list is an ordered collection of elements.
Subscripting Subscripting is supported for string and tuple data types. For example, if x = ('A', 'B', 'C') then x[1] = 'B'. NOTE – Prior to version 2.2, there was only a single “string buffer” for each type of string operation (slicing, concatenation, subscripting, etc.). Subsequent operations of that same type would overwrite previous results. Version 2.2 replaces the fixed string buffers with a small pool of string buffers, usable for any operation.
Printing multiple elements on a single line in SNAPpy produces a slightly different output from how the output appears when printed from Python. Python inserts a space between elements, where SNAPpy does not. SNAPpy also imposes some restrictions on the printing of nested tuples. You may nest tuples; however printing of nested tuples will be limited to three layers deep. The following tuple: (1,'A',(2,'b',(3,'Gamma',(4,'Ansuz')))) will print as: (1,'A',(2,'b',(3,'Gamma',(...
5. SNAPpy Application Development This section outlines some of the basic issues to be considered when developing SNAP-based applications. Event-Driven Programming Applications in SNAPpy often have several activities going on concurrently. How is this possible, with only one CPU on the SNAP Engine? In SNAPpy, the illusion of concurrency is achieved through event-driven programming.
NOTE – the remainder of the flowchart is “chopped off” at this point. It was only being used to make a point, not to show all of SNAP’s internal work-flow.
SNAP Hooks There are a number of events in the system that you might like to trigger some SNAPpy function “handler.” When defining your SNAPpy scripts, there is a way to associate functions with these external events. That is done by specifying a “HOOK” identifier for the function. The following HOOKs are defined: Hook Name When Invoked Parameters HOOK_STARTUP Called on device bootup HOOK_STARTUP passes no parameters.
current count on the internal clock. The same counter is used for all four timing hooks. HOOK_STDIN HOOK_STDOUT Called when “user input” data is received Called when “user output” data is sent • data – A data buffer containing one or more received characters. HOOK_STDOUT passes no parameters.
The old way (required for SNAP versions before version 2.2) – snappyGen.setHook() Somewhere after the routine that you want to be invoked (typically these lines are put at the bottom of the SNAPpy source file), put a line like: snappyGen.setHook(SnapConstants.HOOK_XXX, eventHandlerXXX) where eventHandlerXXX should be replaced with the real name of your intended handling routine. This method still works in the current version, but most people find the new way much easier to remember and use.
For example, to configure UART1 for Transparent (Wireless Serial) mode, put the following statement in your SNAPpy startup handler: crossConnect(DS_UART1, DS_TRANSPARENT) The following table is a matrix of possible Switchboard connections. Each cell label describes the “mode” enabled by row-column cross-connect. Note that the “DS_” prefixes have been omitted to save space.
Local Terminal A command like crossConnect(DS_UART0, DS_STDIO) will send characters received on UART0 to your SNAPpy script for processing. The characters will be reported to your script via your specified HOOK_STDIN handler. Any text “printed” (using the print statement) will be sent out that same serial port. This makes it possible to implement applications like a Command Line Interface.
Sample Application – Wireless UART The following scenario is very common: two devices communicating over an RS-232 serial link. RS-232 serial data cable The two devices might be two computers, or perhaps a computer and a slave peripheral. For the remainder of this section, we will refer to these devices as “end points.” In some cases, a direct physical connection between the two end points is either inconvenient (long distance) or even impossible (mobile end points).
Example of using two SNAP wireless nodes to replace a RS-232 cable Edit this script to specify the OTHER node's address, and load it into a node Node addresses are the last three bytes of the MAC Address MAC Addresses can be read off of the SNAP Engine sticker For example, a node with MAC Address 001C2C1E 86001B67 is address 001B67 In SNAPpy format this would be address "\x00\x1B\x67" """ from synapse.
Here is the source code to SNAPpy script dataModeNV.py """ Example of using two SNAP wireless nodes to replace a RS-232 cable After loading this script into a SNAP node, invoke the setOtherNode(address) function (contained within this script) so that each node gets told "who his counterpart node is.
Code Density When you upload a SNAPpy script to a node, you are not sending the raw text of the SNAPpy script to the node. Instead the SNAPpy source code is compiled into byte-code for a custom Virtual Machine (the SNAPpy VM), and this byte-code and data (SNAPpy “Image”) are sent instead. We have not performed an exhaustive analysis, but a quick check of two typical example scripts (ZicCycle.py and Zic2410i2cTests.py) showed code densities of 11.625 and 13.138 bytes/line of code.
With an RF200, in order to flash an LED connected to the SNAP Engine’s third pin, as we did above with the RF100, you would need to use a command like this (simplified from the above example): pulsePin(6, 500, True) Fortunately, SNAP provides an easy mechanism for simplifying crossplatform coding with the Platform value, stored in NV Parameter 41. SNAP nodes produced by Synapse Wireless will come with this field populated with the node type, e.g., “RF100” or “RF200” or “RF300”.
Now you can simplify your previous code this way: from synapse.platforms import * pulsePin(GPIO_1, 500, True) For an RF100, the GPIO_1 constant will already be defined as 1, and for an RF200 it will already be defined as 6. You don’t need to make any conditional branch in order to affect the same pin on the SNAP-Engine-footprint. Just refer to the pin by its position on the SNAP Engine and the table of constants performs the translation for you. The RF100.py and RF200.
Simplifying the mapping of GPIO pins is only part of the power of the platforms.py file. By having the platform variable defined, you can take advantage of other special features of the various nodes: from synapse.platforms import * if platform == 'RF100': sleepMode = 0 elif platform == 'RF200': sleepMode = 1 sleep(sleepMode, 20) On an RF200, sleep mode 0 results in a significantly higher sleep current than sleep mode 1 does.
Because the platform value’s effects are felt at compile time rather than run time, it is important to make sure you specify the correct value for the target platform any time you export a SNAPpy script to a *.spy file from Portal. (The export window defaults the value to that of the selected node.) Setting the platform variable is as easy to do as setting any other NV Parameter in SNAP. The Device tab of the Configuration Parameters window provides access to the Platform parameter, NV Parameter 41.
6. Invoking Functions Remotely – Function Rpc() and Friends Remote Procedure Call (RPC)-related functionality is such a fundamental part of SNAP and SNAPpy that it is worthy of a section by itself. Refer also to the SNAP Primer for even more basic coverage of this topic, and the SNAP Reference Manual for even more detailed coverage. There are four SNAPpy built-in functions that can be used to invoke a function on another node: • • • • mcastRpc() rpc() callback() callout() These are non-blocking functions.
All of this route seeking and acknowledgement protocol occurs automatically with SNAP. There is nothing the user must “turn on” in order to make it work (though much of the functionality can be fine-tuned through the use of NV parameters). In the above configuration, imagine a situation where node Alice has discovered a route through node Bob to node Carol, and sends node Carol a message.
This is an exaggerated example, but the point is that sometimes you are sending to multiple nodes because of the importance of the command. It is important to note that the function being called might make an RPC call of its own.
a) When the target node does hear the rpc() call, the ACK packet is sent automatically (by the SNAP firmware – you do not send the ACK from your script). b) If the target node does not hear the rpc() call, then it does not know to send the ACK packet. This means the source node will not hear an ACK, and so it will timeout and retry a configurable number of times.
return readAdc(0) def askSensorReading(): value = readSensor() rpc(rpcSourceAddr(),"tellSensorReading", value) which can be simplified even further to: def askSensorReading(): value = readAdc(0) rpc(rpcSourceAddr(),"tellSensorReading", value) You might think that instead of calling rpc(address_of_node_B, "askSensorReading") node A could simply call rpc(address_of_node_B, "readAdc", 0) Although this will result in node B calling his readAdc() function, it won’t actually cause any results to be sent back t
For example, node A could ask node B to read his first analog input channel but tell node C what the answer was. (Imagine for instance that node C has a graphical LCD display that the other nodes lack.
7. Advanced SNAPpy Topics This section describes how to use some of the more advanced features of SNAP.
# read bytes from the selected CBUS device Response = cbusRd(10) # <- you specify how many bytes to read # deselect the CBUS device writePin(somePin, True) # assuming the chip select is active-low CBUS writes are handled in a similar fashion. If you are already familiar with CBUS devices, you should have no trouble using these functions to interface to external CBUS chips. A detailed example of interfacing to an external CBUS voice chip may someday be the topic of an application note.
Some three wire devices are read-only, and you must use function spiRead(). The data width for SPI devices is not standardized. Devices that use a data width that is a multiple of 8 are trivial (send 2 bytes to make 16 bits total for example). However, device widths such as 12 bits are common. To support these “non-multiples-of-8”, you can specify how much of the last byte to actually send or receive.
Interfacing to external I2C slave devices Technically, the correct name for this two-wire serial bus is Inter-IC bus or I2C, though it is sometimes written as I2C. Information on this popular two-wire hardware interface is readily available on the Web; http:/www.i2cbus.org/ is one starting point you could use. In particular look for a document called “The I2C-bus and how to use it (including specifications).
• • • i2cTests.py – This is the overall I2C demo script synapse.M41T81.py – Example of interfacing to a clock/calendar chip synapse.CAT24C128.py – Example of interfacing to an external EEPROM Script i2cTests.py imports the other two scripts, and exercises some of the functions within them. Interfacing to multi-drop RS-485 devices Several of the SNAP Demonstration Boards include an RS-232 serial port.
Nodes that support AES-128 encryption are not available in all jurisdictions. Also, the Si100x platform does not have an AES-128 build available, due to space constraints. (The RF300/RF301 builds, based on the Si100x platform, have external memory available and therefore do have AES-128 builds available.) Users who would like some protection for their data but do not have AES-128 encryption available can use Basic encryption instead.
back to “” to disable encryption. Simply making a serial connection to the node to reset the encryption key will not be sufficient, as serial communications as well as over-the-air communications are encrypted. Recovering an Unresponsive Node As with any programming language, there are going to be ways you can put your nodes into a state where they do not respond.
SNAPpy Scripting Hints The following are some helpful hints (sometimes learned from painful lessons) for developing custom SNAPpy scripts for your nodes. These are not in any particular order. Beware of Case SensitiViTy Like “desktop” Python, SNAPpy scripts are case sensitive – “foo” is not the same as “Foo”. Also, because SNAPpy is a dynamically typed language, it is perfectly legal to invent a new variable on-the-fly, and assign a value to it.
Remember: Serial output Takes Time A script that does: print "imagine a very long and important message here" sleep(mode, duration) …is not likely to be allowing enough time for the text to make it all the way out of the node (particularly at slower baud rates) before the sleep() command shuts the node off. One possible solution would be to invoke the sleep() function from the timer hook. This example hooks into the HOOK_100MS event.
Remember: SNAPpy Integers have a Sign Bit Another side-effect of SNAPpy integers being signed – negative numbers shifted right are still negative (the sign bit is preserved). You might expect 0x8000 >> 1 to be 0x4000 but really it is 0xC000. You can use a bitwise “and” to get the desired effect if you need it. X = X >> 1 X = X & 0x7FFF Pay Attention to Script Output Any SNAPpy script errors that occur can be printed to the previously configured STDOUT destination, such as serial port 1.
As an example, even though a node has no graphics display, it can still generate a plot of link quality over time, by using a code snippet like the following: rpc("\x00\x00\x01", "plotlq", localAddr(), getLq()) For this to do anything useful, Portal must also have loaded a script containing the following definition: def plotlq(who, lq): logData(who, lq, 256) The node will report the data, and Portal will plot the data on its Data Logger pane.
8. Example SNAPpy Scripts The fastest way to get familiar with the SNAPpy scripting language is to see it in use. Portal comes with several example scripts pre-installed in the snappyImages directory. Here is a list of the scripts preinstalled with Portal 2.4, along with a short description of what each script does. Take a look at these to get ideas for your own custom scripts. You can also copy these scripts, and use them as starting points.
Script Name What it does evalBase.py (synapse.evalBase.py) An importable script that adds a library of helpful routines for use with the Synapse evaluation boards. Board detection, GPIO programming, and relay control are just a few examples. EvalHeartBeat.py Example of displaying multiple networking parameters about a node on a single seven-segment display. gpsNmea.py Example decoding of data from a serial GPS.
Script Name What it does protoFlasher.py Just blinks some LEDs on the SN171 Proto Board. protoSleepcaster.py Like McastCounter.py but this script is only for the SN171 Proto Board. Additionally, it demonstrates putting the node to sleep between button presses. PWM.py (synapse.PWM.py) An importable script that adds support for Pulse Width Modulation (PWM) on pin GPIO 0 on platforms based on the MC9S08GB60A chip from Freescale. servoControl.py A second example of using PWM.py.
Scripts Specific to SPI Script Name What it does LTC2412.py (synapse.LTC2412.py) Demonstrates interfacing to an Analog to Digital Converter chip via SPI AT25FS010.py (synapse.AT25FS010.py) Demonstrates interfacing to a 128K FLASH Memory chip via SPI Scripts specific to the EK2100 Kit Refer to the EK2100 Users Guide for more information about these example scripts. Script Name What it does HolidayBlink.py Demonstration for the SN171 Proto Board in the EK2100 kit. HolidayLightShow.
Scripts specific to the RF200 Platform These scripts (all located in the synapse subdirectory of the snappyImages directory) are meant to be run on RF200 SNAP Engines (based on the ATMEL Atmega128RFA1 chip). Script Name What it does pinWakeupATmega128RFA1.py Pin Wakeup functionality specifically for nodes based on the Atmega128RFA1 chip (which includes the RF200). (Imported automatically by pinWakeup.py) RF200.py Platform-specific definitions and enumerations for RF200 Engines.
Script Name What it does PAN4555_PWM.py Controls the additional PWMs on a PAN4555 PAN4555_SE.py Defines the GPIO pins on a PAN4555 SNAP Engine pinWakeupPAN4555_SE.py Configures the “wakeup” pins on a PAN4555 SNAP Engine. (Imported automatically by pinWakeup.py) PAN4561_ledCycling.py Demonstrates extra PWMs on PAN4561 PAN4561_PWM.py Controls the additional PWMs on a PAN4561 PAN4561_SE.py Defines the GPIO pins on a PAN4561 SNAP Engine pinWakeupPAN4561_SE.
Script Name What it does ZicDoodleCtrl.py Uses the potentiometers on the EVB2 board to control an LCD display on an EVB1 board. This script used functions deprecated as of release 2.4. ZicDoodlePad.py Demonstrates the lcdPlot() built-in on a ZIC2410-LCD demonstration board. This script (along with that function) is deprecated. zicHardTime.py How to reference the clock on the nodes based on the ZIC2410 chips. (Imported automatically by hardTime.py) ZicLinkQuality.
Script Name What it does STK600demo.py Implements an up/down binary timer on the STK600 demo board. Push the button to reverse the direction. Scripts specific to the SM700/MC13224 Platforms These scripts are meant to be run on the Synapse SM700 surface-mount module, or the Freescale MC13224 chip on which it is based, or on a compatible board that uses one of the two. Script Name What it does MC13224_PWM.py Demonstrates Pulse Width Modulation on the TMR0/TMR1/TMR2 pins (GPIO8-10).
Script Name What it does STM32W108xB_ledCycling.py Uses the PWM support routines in STM32W108xB_PWM.py to vary the brightness of an LED attached to the PB6 (IO14) pin. By changing the script, the PWM functionality can be demonstrated on the other 11 PWM capable pins pinWakeupSTM32W108xB.py Shows how to implement advanced hardware features from SNAPpy scripts, in this case how to access the “wake up” functionality of the chip STM32W108xB_sleepTests.
Technique Example scripts that demonstrate this technique Performing actions at startup, including using the @setHook() function to associate a user-defined function with the HOOK_STARTUP event CommandLine.py DarkDetector.py DarkRoomTimer.py EvalHeartBeat.py gpsNmea.py ledToggle.py LinkQualityRanger.py McastCounter.py protoFlasher.
Technique Example scripts that demonstrate this technique Controlling a GPIO pin using writePin(), etc. buzzer.py evalBase.py gpsNmea.py ledToggle.py protoFlasher.py protoSleepCaster.py Generating a short pulse using pulsePin() buzzer.py Reading an analog input using DarkDetector.py readAdc(), including auto-ranging at run-time Performing periodic actions, including the use of @setHook() to associate a user defined routine with the HOOK_100MS event or other timed events buzzer.py DarkDetector.
Technique Example scripts that demonstrate this technique Thresholding, including periodic sampling and changing the threshold at run-time DarkDetector.py Discovering another node with a needed capability DarkDetector.py Advertising a service to other wireless nodes buzzer.py Adding new capabilities by writing directly to processor registers (peek() and poke()) pinWakeup.py Writing parameters to Non-volatile (NV) storage evalBase.py PWM.py [Platform]HardTime.py DatamodeNV.
Technique Example scripts that demonstrate this technique Displaying hexadecimal data on the seven-segment display EvalHeartBeat.py McastCounter.py sevenSegment.py Displaying custom characters on the seven-segment display DarkRoomTimer.py Configuring Transparent Mode AKA Data Mode datamode.py Varying LED brightness using Pulse Width Modulation ledCycling.py EvalHeartBeat.py dataModeNV.py PAN4555_ledCycling.py PAN4561_ledCycling.py ZIC2410ledCycling.py MC13224_ledCycling.py MC13224_PWM.