C/C++ Client
Installation
The Basics
Initialization
Cloud Variables
Notifications
Synchronization
Error Handling
Installation
The Canopy C/C++ Client is part of the Canopy Embedded Development Kit (EDK). The EDK uses repo, which is a tool that makes it easier to work with multiple git repositories.
Prerequisites
Installing Required Packages (Ubuntu 14.04)
sudo apt-get install g++ git rpm cmake zlib1g-dev libssl-dev curl libcurl4-openssl-dev dialog
Installing Repo

Download repo and put it somewhere in your PATH:

curl https://storage.googleapis.com/git-repo-downloads/repo > repo
chmod a+x repo
sudo cp repo /usr/local/bin
Downloading the Source
Initializing a Repo Client

After installing repo, set up your client to access the Canopy EDK repository.

1) Create a working directory. You can call it anything you like:

mkdir canopy_edk
cd canopy_edk

2) Run repo init to initialize the client repository.

repo init -u https://github.com/canopy-project/canopy-embedded-manifest

To check out a branch other than "master", specify it with -b:

repo init -u https://github.com/canopy-project/canopy-embedded-manifest -b beta

3) Use repo sync to download sources to your working directory:

repo sync
Building and Installing libcanopy
Initializing the Build Environment
Canopy's build system expects certain environment variables to be set, which are initialized with the envsetup.sh script. Use this script to select the target platform and build flavor (i.e. debug or release).

For example, from the build/ directory:
source envsetup.sh linux-default debug
If you have dialog installed on your system, you can interactively configure your build by simply running:
source envsetup.sh
If you do not have dialog installed, the envsetup.sh script will simply list the available options.
Building and Installing

To build and install the Canopy EDK, from build/ run:

make
sudo make install
The Basics
A Simple Example
This simple program initializes libcanopy and posts some data to the cloud. Error checking is omitted for clarity.
#include <canopy.h>

int main(void) {
    CanopyContext ctx;
    float32 humidity = 0.0;

    ctx = canopy_init_context();

    canopy_set_opt(
        CANOPY_CLOUD_HOST, "sandbox.canopy.link",
        CANOPY_DEVICE_UUID, <YOUR UUID HERE>
        CANOPY_DEVICE_SECRET_KEY, <YOUR SECRET KEY HERE>
    );

    canopy_var_init(ctx, "out float32 humidity");

    // Your sensor-reading code goes here.
    //humidity = ReadHumiditySensor();

    canopy_var_set_float32(ctx, "humidity", humidity);

    canopy_sync_blocking(ctx, 10000);

    return 0;
}
Compiling and Running
Compiling

You can compile your program with a normal C/C++ compiler, such as GCC.

When you installed libcanopy it should have copied canopy.h to somewhere in your include path, such as /usr/local/include/canopy.h. If

libcanopy
is not in your path you will need to add it with something like:

gcc -Wall -g -I~/canopy_edk/libcanopy/include -C example.c -o example.o
Linking

You must link your program with the following shared libraries:

  • libcanopy
  • libsddl
  • libred-canopy
  • libwebsockets-canopy or libwebsockets
  • libcurl

Some of the libraries that libcanopy depends on, such as libwebsockets are included in the EDK repo. The EDK build system will append -canopy to the library object file name (for example libwebsockets-canopy) in order to prevent collisions with other versions of those libraries that may already be installed on your system.

gcc -Wall -g -lred-canopy -lcanopy -lsddl -lcurl -lwebsockets-canopy example.o -o example

If you haven't installed libcanopy, you may need to add the appropriate directory(ies) to the library path. For example:

gcc -Wall -g -L~/canopy_edk/build/_out/lib -lred-canopy -lcanopy -lsddl -lcurl -lwebsockets-canopy example.o -o example
Running

If you've installed libcanopy, you should be able to just run your program, for example, with:

./example

You may need to add the appropriate path to LD_LIBRARY_PATH or DYLD_LIBRARY_PATH:

LD_LIBRARY_PATH=~/canopy_edk/build/_out/lib ./example
Initialization
canopy_init_context
CanopyContext canopy_init_context();

Initialize libcanopy and create a context.

This may be called multiple times to create multiple contexts, which may be useful for unit testing, or if you need to talk to multiple canopy servers.

The new context is configured based on environment variables, falling back to default settings.

Returns a handle to the newly-create context object. Returns NULL on error.

Example
CanopyContext ctx;
ctx = canopy_init_context();
if (!ctx) {
    canopy_write_error(stderr, NULL, "Failed to initialize Canopy context");
}
canopy_set_opt
CanopyResultEnum canopy_set_opt(CanopyContext ctx, 
        [OPTION_NAME, OPTION_VALUE,]
        ...
);

Set a context-wide option.

Takes an odd number of arguments. After the first argument (ctx), the arguments must must alternate between option identifiers and values. The option pars may appear in any order, but each option may be provided at most once.

Accepted options are:

  • CANOPY_CLOUD_HOST
  • CANOPY_HTTP_PORT
  • CANOPY_HTTPS_PORT
  • CANOPY_WS_PORT
  • CANOPY_WSS_PORT
  • CANOPY_DEVICE_UUID
  • CANOPY_DEVICE_SECRET_KEY

Returns CANOPY_SUCCESS on success, otherwise an error code.

Example
CanopyResultEnum result;

// Does nothing with no option arguments:
canopy_set_opt(ctx);

// You can set several options at once:
result = canopy_set_opt(ctx,
    CANOPY_CLOUD_SERVER, "localhost:8080",
    CANOPY_DEVICE_UUID, "16eeca6a-e8dc-4c54-b78e-6a7416803ca8",
    CANOPY_DEVICE_SECRET_KEY, "My Secret"
);
if (result != CANOPY_SUCCESS) {
    canopy_write_error(stderr, ctx, "Failed to set options");
}
Cloud Variables
canopy_var_init
CanopyResultEnum canopy_var_init(CanopyContext ctx, 
        const char *decl,
        [OPTION_NAME, OPTION_VALUE,]
        ...
);
canopy_var_set
CanopyResultEnum canopy_var_set(CanopyContext ctx, const char *varname, CanopyVarValue value);

CanopyResultEnum canopy_var_set_bool(CanopyContext ctx, const char *varname, bool value);
CanopyResultEnum canopy_var_set_float32(CanopyContext ctx, const char *varname, float value);
CanopyResultEnum canopy_var_set_float64(CanopyContext ctx, const char *varname, double value);
CanopyResultEnum canopy_var_set_int8(CanopyContext ctx, const char *varname, int8_t value);
CanopyResultEnum canopy_var_set_int16(CanopyContext ctx, const char *varname, int16_t value);
CanopyResultEnum canopy_var_set_int32(CanopyContext ctx, const char *varname, int32_t value);
CanopyResultEnum canopy_var_set_string(CanopyContext ctx, const char *varname, const char *value);
CanopyResultEnum canopy_var_set_uint8(CanopyContext ctx, const char *varname, uint8_t value);
CanopyResultEnum canopy_var_set_uint16(CanopyContext ctx, const char *varname, uint16_t value);
CanopyResultEnum canopy_var_set_uint32(CanopyContext ctx, const char *varname, uint32_t value);
canopy_var_get
canopy_var_on_change
CANOPY_VALUE_ macros
CANOPY_READ_ macros
Notifications
canopy_notify
Synchronization
canopy_sync_blocking
canopy_once_every
Error Handling
Error Codes
Most libcanopy routines return an error code, indicating success or the reason for failure.
Enum Value Meaning
CANOPY_SUCCESS Command succeeded
ERROR_UNKNOWN An unknown error occured
CANOPY_ERROR_CONNECTION_FAILED Unable to connect to cloud server.
CANOPY_ERROR_REDUNDANT_PARAMETER A single parameter was provided too many times to a routine.
CANOPY_ERROR_PROMISE_NOT_COMPLETE The requested operation cannot be performed on a non-completed promise.
CANOPY_ERROR_INVALID_OPT A supplied option was invalid.
CANOPY_ERROR_OUT_OF_MEMORY You need to add more RAM :-)
CANOPY_ERROR_BAD_VARIABLE_DECLARATION Cloud Variable declaration could not be parsed.
CANOPY_ERROR_SINGLE_USE_VALUE_ALREADY_USED A single-use Cloud Variable value has already been used as an argument.
CANOPY_ERROR_INCORRECT_DATATYPE The provided datatype does not match the dataype expected.
CANOPY_ERROR_INVALID_VALUE An invalid value was provided as a parameter.
CANOPY_ERROR_PARSING_PAYLOAD Unable to parse received payload.
CANOPY_ERROR_PROCESSING_PAYLOAD Error processing received payload.
canopy_error_msg
canopy_write_error