Introduction

Background

Synapse Wireless provides a tremendously flexible mesh networking solution that allows you to put a lot of your interpret-and-control intelligence at the outer edges of your network. SNAP devices accept your custom programs in the Python-based SNAPpy scripting language, so you can make decisions about outputs and messaging based on the device’s environment or on messages from its neighbors.

SNAPpy scripting provides a great deal of power and control with a relatively low learning curve, but that comes at a cost. The processor overhead involved in running a high-level language like Python and the restrictions that SNAPpy requires (such as 16-bit integers and no floating-point math) mean that there are some things that you just can’t do well with SNAPpy. SNAPpy has always provided a limited way around this with the built-in call() function, which allows you to invoke code written in C (or assembly) by passing in a string constant of the code to run. But even this had limitations: there was no persistence of data between calls, your code size was limited to 255 bytes, and accessing other SNAP functionality from your C code wasn’t an option.

Now, however, you can allocate space for persistent data, and your program size is limited only by the available flash space. Some of the integrated SNAP functionality is also available as function calls. And the new C support works seamlessly with your Python-based SNAPpy script, so you don’t need to write any more C code than is necessary for your application.

Requirements

To take advantage of the new support for running C code, you have to work within a few simple restraints:

  • You must use SNAP 2.7 or later in an ATmega128RFA1-based SNAP device, such as an RF200, RF220, SM220, SN220, etc.

  • You must use version 6.x of the IAR Systems Embedded Workbench for AVR as your C compiler.

    • GCC or other compilers are not supported.
    • You can use the full version of IAR Embedded Workbench if you have a license to do so. This imposes no restrictions on the size of your compiled code and provides all the normal support one would expect from IAR Systems.
    • You can also use the “Kickstart” version of IAR Embedded Workbench. This feature-limited installation restricts the size of your compiled code to 4 kilobytes and imposes other restrictions, but it allows for commercial development without paying for a full license.
  • You must use the new SNAPbuild command-line tool to generate the .spy file. Portal does not have the ability to incorporate your C code into the file loaded into your device, though you can still use Portal to load the .spy file into your device, and you can invoke (properly wrapped) C functions in your code from Portal’s Node Info or Command Line panes.

Basic Workflow

Writing your SNAPpy scripts with C support should be fairly easy for anyone who has both SNAPpy and C experience. A few extra commands and function decorators in your SNAPpy script notify SNAPbuild that you are including C code. Add an API definition in either your SNAPpy script or your C code, and SNAPbuild does the rest for you. This is much easier than working with C code using the call() function, which required stack manipulation in order to access parameters.

  1. Write the parts of your script that are appropriate for SNAPpy scripting in the Python-based SNAPpy language. You can do this in Portal or the IDE of your choice.
  2. Write your C functions using the development environment of your choice. If you have a favorite IDE, you are welcome to use it. You may find that the IAR Embedded Workbench for AVR simplifies some of your work, as it provides appropriate header files for things like accessing registers by the names provided in the ATmega128RFA1 data sheet. However, while we do require that the compiler be installed in order to create the .spy file, once you have the software installed, registered, and configured, there is no requirement that you write your code using it.
  3. In your SNAPpy script, add function stubs by using function decorators, indicating that the stubs refer to functions in the C code. Then, add an import function call at the top of your SNAPpy script referencing your C code file.
  4. Run SNAPbuild (from the command line) to generate the .spy file, which you can then load into your devices using Portal or SNAPconnect. (You can also use SNAPbuild to create .spy files when there is no C code involved, if you so desire.)

The SNAPbuild program generates a number of files necessary to complete the placement and linking of your C code alongside the SNAPpy code. Each of these files will be rebuilt every time you run SNAPbuild, so there is nothing to be gained by modifying them. There may be value in reading them, though, if you are interested in infrastructure. The most important of these are:

snappy.h
As mentioned before, you must #include this header file in your C code file. It includes type definitions and some constants used by the C code generated by SNAPbuild, plus a few macros to assist with your access of variables.
snap_utils.h

This header file contains function prototypes for several bits of built-in functionality available to you. If you want to access these functions from your C code, you must #include this header file. Available functions are:

  • random provides a 12-bit random number, just as the random() function in SNAPpy does.
  • writePin allows you to set a pin state by simple call, rather than poking registers. The pin must first be defined as an output pin, presumably in your SNAPpy code.
  • pulsePin allows you to set a pin to pulse for the specified duration, just as from the SNAPpy pulsePin() function.
  • readPin returns 1 or 0 as the current True or False value for whether the specified pin is high.
  • pyerr allows you to specify your own return error codes that you can check from your SNAPpy script using the errno() built-in function. The return value should be a one byte unsigned integer. You can also use this as a back-channel means to return a second value from your function if you don’t wish to pack an extra byte into a returned string.
snap_utils.c
This file contains pointers to the entry addresses for the built-in functions in SNAP that are prototyped in the snap_utils.h header file. These addresses will change for different firmware versions and different platforms, so you must not assume that the addresses are things you should call outside the mechanism provided here.
main.c
This file contains wrapper functions that handle the interface between the SNAPpy world and the C world. It also contains the function prototypes for your C functions, automatically generated by SNAPbuild.
build.log
This log file tracks the compilation and linking commands used in the process, as well as their results. It is a useful resource if you need to do any troubleshooting.

These files are built in a directory that is a child of the output directory specified for SNAPbuild. By default, the output directory is the working directory. If you were to run SNAPbuild on a SNAPpy file named my_file.py, the files would be located in my_file_c_build within your output directory.