AWS Greengrass Core SDK for C
AWS Greengrass Core SDK for C Documentation

Overview

The AWS Greengrass Core SDK for C provides an interface to interact with the Greengrass Core system on the edge. It is c89 compliant and is meant to be performant while minimizing dependencies.

AWS Greengrass Core SDK for C is now in General Availability.

Requirements

Building the SDK

Clone the SDK into local workspace:

1 git clone https://github.com/aws/aws-greengrass-core-sdk-c.git

Build the SDK:

1 cd aws-greengrass-core-sdk-c
2 mkdir build && cd build
3 cmake ..
4 cmake --build .

The build will produce a shared object named libaws-greengrass-core-sdk-c.so under the build/aws-greengras-core-sdk-c directory. This is the shared object that the Lambda executable links to.

Note:

Building Greengrass Native Lambda Executables with CMake

You can use CMake to build Greengrass Lambda executables. Other build tools could work as well. Here cmake is shown as an example:

Setting up a CMake Project

Create a directory to hold your project:

1 mkdir my_gg_native_function

Open the directory and add a CMakeLists.txt file that specifies your project's name, executables, source files, and linked libraries. The following is a minimal example:

1 # minimal CMakeLists.txt for the AWS Greengrass SDK for C
2 cmake_minimum_required(VERSION 2.8)
3 # "my_gg_native_function" is just an example value.
4 project(my_gg_native_function)
5 
6 # Locate the AWS Greengras SDK for C package.
7 # Requires that you build with:
8 # -Daws-greengrass-core-sdk-c_DIR=/path/to/sdk_build
9 # or export/set:
10 # CMAKE_PREFIX_PATH=/path/to/sdk_build
11 find_package(aws-greengrass-core-sdk-c REQUIRED)
12 
13 add_executable(my_gg_native_funtion main.cpp)
14 target_link_libraries(my_gg_native_funtion aws-greengrass-core-sdk-c)

To get started quickly, there are several pre-made examples in the aws-greengras-core-sdk-c-example directory for your reference. Those examples are built along with the SDK.

Creating Deployment Package

After the Lambda executable is built, it should be packaged into a deployment package, which is a zip file consisting of your executable and any dependencies. Then you can upload the package to AWS Lambda and deploy it to a device by following the normal AWS Greengrass process.

Using the SDK

Initialization

All code that uses the AWS Greengrass SDK for C must do gg_global_init() before calling any other APIs and gg_runtime_start() to start the runtime, as follows:

1 #include "greengrasssdk.h"
2 
3 void handler(const gg_lambda_context *cxt) {
4  /* Your lambda logic goes here. */
5 }
6 
7 int main() {
8  gg_global_init(0);
9  /* start the runtime in blocking mode. This blocks forever. */
10  gg_runtime_start(handler, 0);
11 }

Reading Event Payload

To read the event payload for the Lambda handler to process, use gg_lambda_handler_read(). The amount of data written into the buffer is not guaranteed to be complete until amount_read is zero.

The following is a sample usage of the method:

1 /* loop read handler event into buffer. */
2 gg_error loop_lambda_handler_read(void *buffer,
3  size_t buffer_size, size_t *total_read) {
4  gg_error err = GGE_SUCCESS;
5  uint8_t *read_index = (uint8_t*)buffer;
6  size_t remaining_buf_size = buffer_size;
7  size_t amount_read = 0;
8 
9  do {
10  err = gg_lambda_handler_read(read_index, remaining_buf_size,
11  &amount_read);
12  if(err) {
13  gg_log(GG_LOG_ERROR, "gg_lambda_handler_read had an error");
14  goto cleanup;
15  }
16  *total_read += amount_read;
17  read_index += amount_read;
18  remaining_buf_size -= amount_read;
19  } while(amount_read);
20 
21 cleanup:
22  return err;
23 }

Writing Handler Response

After the Lambda handler finishes processing, a response can be returned using gg_lambda_handler_write_response(). If this method is not called, an empty response will be returned.

Writing Handler Error Response

When the Lambda handler encounters any error, the error response can be returned to the caller using gg_lambda_handler_write_error().

Initialize API Request

Every API request must be initialized using gg_request_init() before making the actual request.

Reading API Response

There are several cases which require reading a response after an API call, such as gg_invoke(), gg_get_thing_shadow(), etc. gg_request_read() should be used after the method call to retrieve the output response.

The following is a sample usage of the method:

1 /* loop read request bytes into buffer. */
2 gg_error loop_request_read(gg_request ggreq, void *buffer,
3  size_t buffer_size, size_t *total_read) {
4  gg_error err = GGE_SUCCESS;
5  uint8_t *read_index = (uint8_t*)buffer;
6  size_t remaining_buf_size = buffer_size;
7  size_t amount_read = 0;
8 
9  do {
10  err = gg_request_read(ggreq, read_index, remaining_buf_size,
11  &amount_read);
12  if(err) {
13  gg_log(GG_LOG_ERROR, "gg_lambda_handler_read had an error");
14  goto cleanup;
15  }
16  *total_read += amount_read;
17  read_index += amount_read;
18  remaining_buf_size -= amount_read;
19  } while(amount_read);
20 
21 cleanup:
22  return err;
23 }

Error Handling

When there is an error on method call, all the APIs have gg_error returned as the return code. And for gg_publish_with_options(), gg_publish(), gg_invoke() and gg_xxx_thing_shadow() APIs, you can check server side error from request status from the gg_request_result() struct.

Opening Issues

If you encounter a bug with the AWS Greengrass SDK for C, we would like to hear about it. Search the existing issues and see if others are also experiencing the issue before opening a new issue. When creating issue, please fill in the following template:

1 [Problem Description]: Describe the problem in detail
2 [Reproduction Steps]: Describe the steps in detail
3 [Target OS/Architecture]: eg. x86_64 Ubuntu 16.04
4 [Greengrass Core Version]: eg. 1.6.0
5 [Greengrass Core SDK for C Version]: eg. 1.0.0
6 [Compiler and Version] : eg. GCC 5.0 / LLVM 7
7 [Cmake Version] eg. Cmake 3.2
8 [Logs] runtime.log, lambda log