To run the Google Cloud IoT Device SDK for Embedded C on new platforms, first read the Building section to adapt the make
environment to your toolchain. Then, review the Porting section to customize the Board Support Package (BSP) for the target device.
Before you port the Device SDK to a new platform, review the README.md
in the root directory of this repository and be familar with the default build process.
This document is for embedded device developers who want to run the Device SDK on their custom device.
This document provides details of the Device SDK's build steps, build configuration flags, and the location of the functions needed to port the SDK to new platforms.
For general information about the Device SDK's features and application usage, see the user guide in docs/user_guide.md
.
The Device SDK accommodates a variety of IoT devices. Default host/target support is provided for POSIX systems (tested on Ubuntu Linux). The Device SDK was also tested on RTOS and no-OS devices.
Most of the codebase is cross-platform and resides in the src/libiotc/
directory. Platform-specific code is in the src/bsp/
directory.
The codebase is built against C99 standards.
This section describes how to configure make to cross-compile the Device SDK for your platform.
We recommend building the Device SDK for a Linux distribution before cross-compiling to another target platform. Building for Linux introduces you to the basic architecture and tools of the Device SDK source. This basic knowledge then helps you cross-compile the software to an embedded device.
The Device SDK builds its source files with make
. The main makefile is in the root directory of the repository.
Depending on the build configuration, the main makefile includes more make-related (.mk) files that alter the list of compiled source files and toolchain command line arguments. Three flags in the main makefile specify the build configuration: TARGET
, CONFIG
and IOTC_BSP_TLS
.
-
TARGET
determines the platform for which you're compiling. This affects toolchain flags, file pathing, and BSP sources. If this flag isn't specified, it defaults toTARGET=linux-static-release
orTARGET=osx-static-release
, depending your host system. OS X host builds are unsupported. -
CONFIG
determines the Device SDK software modules, like the memory limiter or debug logging, that the system compiles into the library. This value defaults toCONFIG=posix_fs-posix_platform-tls_bsp-memory_limiter
for local POSIX machine development. -
IOTC_BSP_TLS
determines the Transport Layer Security (TLS) BSP implementation that the makefile compiles. The TLS BSP selection configures the Device SDK to encrypt data sent from the Device SDK over the network socket with the desired embedded TLS library. The default value of this flag isIOTC_BSP_TLS=mbedtls
; the default implemenation is insrc/bsp/tls/mbedtls
. This also configures the build system to do cryptographic key signatures in mbedTLS via the implementation insrc/bsp/crypto/mbedtls
. The flag for the out-of-the-box wolfSSL implemenation, which resides insrc/bsp/tls/wolfssl
andsrc/bsp/crypto/wolfssl
, isIOTC_BSP_TLS=wolfssl
. Both of these implementations configure and build the third-party TLS library sources in thethird_party/tls/mbedtls
orthird_party/tls/wolfssl
, respectively. The build system prompts the user with instructions on how to populate these directories with the required TLS library sources.- The sources for the third-party TLS libraries aren't included in the repo by default. The
make
command automatically downloads mbedtls and configures it for the Device SDK. Themake
command doesn't automatically download wolfSSL; however, runningmake
automatically provides instructions on how and where to download wolfSSL. - To define your own BSP implementation, see the TLS BSP section later in this document.
- If you use a hardware TLS instead of a software TLS, compile without a TLS BSP and invoke the Device SDK's secure socket API directly from the Device SDK's networking BSP. To compile without a TLS BSP, follow the additional steps below.
- Do not define
IOTC_BSP_TLS
on themake
command line. - Change the
tls_bsp
config parameter totls_socket
. For example, runmake CONFIG=posix_fs-posix_platform-tls_socket-memory_limiter
.
- Do not define
- The sources for the third-party TLS libraries aren't included in the repo by default. The
Specific CONFIG
options are described in the CONFIG
and TARGET
parameters section.
Although the make
build system is suitable for Linux/Unix builds, some embedded SDKs and toolchains may not support building via make
. Often, these SDKs supply their own Integrated Development Environments (IDEs).
Before importing the Device SDK's source into an IDE, create a native Device SDK build on POSIX to see the following useful information for your IDE's preprocessor environment settings.
- A list of the source files that were compiled (.c)
- A list of the preprocessor definitions that were required for the build
CONFIG
you selected (-D) - The flags passed to the compiler/toolchain
- The header file include paths that were used (-I)
- the link paths that were used to link a binary (-L)
- the linker library names that were used (-l)
Execute the following commands for more information about the build environment.
-
Run
make MAKEFILE_DEBUG=1
to log all makefile variables and their corresponding values. -
Run
make MD=
on a clean build to log all of the commands, executables, and parameters that are created during to build process.make MD=
also executes all of the logged commands. -
make -n
is likemake MD=
butmake -n
doesn't execute the logged commands.
The CONFIG
and TARGET
parameters are defined on the command line. For additional information about CONFIG
and TARGET
, see Build environment.
Parameter values consist of a multi-component, single-string listing of module names. Spaces are not permitted; seperate modules with the hyphen ('-') character.
A typical TARGET
argument consists of a platform flag, an output library flag and a build type flag.
make TARGET=linux-static-debug
[ linux | osx | arm-linux ]
- Sets the target platform. The continuous integration services usesarm-linux
to smoke-test cross-compliled builds. OS X is currently unsupported.
[ static | dynamic ]
- Sets the output library type.
[ debug | release ]
- Sets the build type. Thedebug
option passes the standard toolchain debug symbols to the compiler. Thedebug
option also provides runtime debug output from the library by adding theIOTC_DEBUG_OUTPUT=1
preprocessor definition. To suppress this, appendIOTC_DEBUG_OUTPUT=0
to themake
command.
A typical CONFIG
argument consists of an option feature flag, a file system flag, a development flag, and a platform sector flag.
make CONFIG=posix_fs-posix_platform-tls_bsp-memory_limiter
threading
- POSIX only. Causes publication, subscription, and connection callbacks to be called on separate threads. If not set, application callbacks are called on the main thread of the Device SDK's event system.
The file system flag is for reading public root CAs for service authentication during the TLS handshake.
posix_fs
- POSIX implementation of file system calls.memory_fs
- A file system compiled into memory.dummy_fs
- Empty implementation for testing purposes.expose_fs
- Adds a new API function that allows the external definition of file system calls.
memory_limiter
- Enables memory limiting and monitoring to simulate caps on the available amount of memory. Additionally, a memory monitor tracks memory leaks while testing. Ifposix_platform
is defined, then the Device SDK also logs a stack trace of the initial allocation.mqtt_localhost
- Instructs the Device SDK's MQTT client to connect to a localhost MQTT server instead of the Cloud IoT Core MQTT bridge.no_certverify
- Disables TLS certificate verification of the service's identifying cert to reduce security. For development purposes only.tls_bsp
- Instructs the Device SDK's MQTT client to use third-party TLS 1.2 implementations to encrypt data before sending it over network sockets.tls_socket
- Counterpart oftls_bsp
. Prevents the MQTT client from including a TLS layer that invokes a TLS BSP. This increases network security. Note that the Cloud IoT Core MQTT bridge will not accept connections without TLS.
- posix_platform - Selects the implementation for non-BSP time and memory solutions
Platform configurations configure the build system to include critical section implementations for invoking callbacks on new threads.
For best results, define posix_platform
and omit threading
from your CONFIG
options when building for custom platforms. threading
is currently omitted by default.
For more information about threadsafe callback support, see the user guide in doc/user_guide.md
.
Application binaries and sources are in the examples/
directory.
These examples use the Device SDK to connect to Cloud IoT Core, subscribe to Cloud Pub/Sub topics, publish information to Cloud IoT Core, and receive data from Cloud IoT Core.
The examples' source code shows you how to initialize and use the Device SDK's C API. For more information about the C API, consult the comments in the example code, README.md
, doc/user_guide.md
, and the API reference.
To build the examples follow the instructions in the main README.md
.
This section describes how to customize the BSP. After adapting the make
environment to your toolchain, customize the BSP for your device to port the Device SDK to a new platform.
The Board Support Package (BSP) is the well-defined set of functions that the Device SDK invokes in order to interact with a platform's specific networking, file IO, TLS, memory management, random number generator, crypto, and time SDKs.
The BSP implementation is in the src/bsp
directory. When porting the Device SDK to your platform SDK, ignore the MQTT codec and the non-blocking/asynchronous engine that appear elsewhere in the source.
BSP function declarations are in the include/bsp
directory. For generated function documentation, see the Device SDK BSP reference.
BSP functions are organized into logical subsystems as follows.
- BSP IO NET: networking stack integration (
include/bsp/iotc_bsp_io_net.h
) - BSP TLS: Transport Layer Security integration (
include/bsp/iotc_bsp_tls.h
) - BSP MEM: heap memory management (
include/bsp/iotc_bsp_mem.h
) - BSP RNG: random number generator (
include/bsp/iotc_bsp_rng.h
) - BSP CRYPTO: ECC, SHA256, Base64 (
include/bsp/iotc_bsp_crypto.h
) - BSP TIME: time function (
include/bsp/iotc_bsp_time.h
)
Reference function implementations of POSIX BSPs and supported TLS libraries are provided in the src/bsp/platform
, src/bsp/tls
, and src/bsp/crypto
directories.
The platform
directory contains reference BSP implementations for networking, file IO, memory management, random number generation, and time functionality. The tls
directory contains reference BSP implementations for cryptographic functionality and TLS support via the mbedTLS or wolfSSL libraries, which supply secure TLS v1.2 connections over TCP/IP for embedded device footprints.
A POSIX platform implementation is provided for your reference in the src/bsp/platforms/posix
directory.
If your target platform is not POSIX compliant (most IoT embedded devices are not POSIX compliant), complete the following steps.
- Create a new implementation in a new directory
src/bsp/platform/NEW_PLATFORM_NAME
. For reference, see the BSP headers and generated documentation. - Call
make
with the parameterIOTC_BSP_PLATFORM=NEW_PLATFORM_NAME
.
mbedTLS
and wolfSSL
TLS BSP implementations are in the src/bsp/tls/mbedtls
and src/bsp/tls/wolfssl/
directories, respectively, with Key signature functionaly leveraged in src/bsp/crypto/mbedtls
and src/bsp/crypto/wolfssl
, respectively. The BSP TLS implementations are in src/bsp/tls/mbedtls/iotc_bsp_tls_mbedtls.c
and src/bsp/tls/wolfssl/iotc_bsp_tls_wolfssl.c
. The corresponding cryptographic implementations (for JWT signing) are in src/bsp/crypto/mbedtls/iotc_bsp_crypto.c
and src/bsp/crypto/wolfssl/iotc_bsp_crypto.c
.
If neither mbedTLS nor wolfSSL fits your target platform or licensing requirements, you can configure the build system to use other TLS BSP implementations.
Make sure the custom TLS BSP meets the TLS Implementation Requirements defined in doc/user_guide.md
.
Complete the following steps to create a new BSP implementation for TLS.
- Implement the BSP TLS API functions in
include/bsp/iotc_bsp_tls.h
. Refer to at least one of the mbedTLS or wolfSSL implementations throughout this process to guide your development. - Create a directory
src/bsp/tls/NEW_TLS_LIBRARY_NAME
and a directorysrc/bsp/crypto/NEW_TLS_LIBRARY_NAME
to store the new TLS and crypto implementation. - Copy the file
make/mt-config/mt-tls-mbedtls.mk
tomake/mt-config/mt-tls-NEW_TLS_LIBRARY_NAME.mk
. - Redefine the path variables in
make/mt-config/mt-tls-NEW_TLS_LIBRARY_NAME.mk
according to the new TLS library's internal directory structure, relative to the base directory of the main makefile:- IOTC_TLS_LIB_INC_DIR is added to the toolchain include path when the Device SDK compiles.
- IOTC_TLS_LIB_DIR is added to the TLS library when linking it to a client application on a new platform.
- IOTC_TLS_LIB_NAME is added as a
-l
library name parameter when linking the TLS library to a client application on a new platform. - IOTC_TLS_LIB_DEP is a path to a library as a makefile dependency. The build will fail and warn you if this file is missing. See
make/mt-config/mt-tls.mk
for more information. - IOTC_CONFIG_FLAGS (optional) augments the subsequent compile-time preprocessor flags. Append to this value only with the makefile += operator.
- Call
make
with the parameterIOTC_BSP_TLS=NEW_TLS_LIBRARY_NAME
.- The library name must match the directory name you created under
src/bsp/tls
above. Additionally, this command doesn't build your TLS library directly. Instead, it builds your TLS BSP to work with that library. - To build your custom library and the mbedTLS and wolfSSL libraries, refer to
make/mt-config/mt-tls.mk
and the shell scripts inres/tls
.
- The library name must match the directory name you created under
After building the SDK and TLS static libraries, follow the instructions below to link the libraries to a client application on a new platform.
The existing platform config files make/mt-os/mt-linux.mk
and make/mt-os/mt-osx.mk
demonstrate how to link the libraries to Linux and OS X, respectively.
-
Create a new file
make/mt-os/mt-NEW_PLATFORM_NAME.mk
.-
Include the common
mt
file.include make/mt-os/mt-os-common.mk
-
Define CC and AR. Provide the full path to your toolchain's compiler and archiver executables. For example, the following definitions are for a FreeRTOS build.
CC = ~/downloads/FreeRTOS_sdk/FreeRTOS_tools/bin/armcl AR = ~/downloads/FreeRTOS_sdk/tools/bin/armar
-
Add compiler flags by appending them to variable IOTC_COMMON_COMPILER_FLAGS. For example:
IOTC_COMMON_COMPILER_FLAGS += -I~/downloads/FreeRTOS_sdk/include IOTC_COMMON_COMPILER_FLAGS += -DFreeRTOS
-
Set flags specific to the C and C++ compiler in IOTC_C_FLAGS and IOTC_CXX_FLAGS, respectively.
-
Add archiver flags by appending them to the IOTC_ARFLAG variable.
IOTC_ARFLAGS := r $(XI)
-
-
Add details about the new platform to
make/mt-config/mt-presets.mk
.-
Define the Device SDK feature and target configurations.
CONFIG_<i><b>NEW_PLATFORM_NAME</b></i>_MIN = memory_fs-tls_bsp TARGET_<i><b>NEW_PLATFORM_NAME</b></i>_REL = -static-release
-
Define make system variables for
PRESET NEW_PLATFORM_NAME
else ifeq ($(PRESET), <i><b>NEW_PLATFORM_NAME</b></i>) CONFIG = $(CONFIG_<i><b>NEW_PLATFORM_NAME</b></i>_MIN) TARGET = $(TARGET_<i><b>NEW_PLATFORM_NAME</b></i>_REL) IOTC_BSP_PLATFORM = <i><b>NEW_PLATFORM_NAME</b></i> IOTC_TARGET_PLATFORM = <i><b>NEW_PLATFORM_NAME</b></i>
-
-
Extend
make/mt-os/mt-os.mk
to checkTARGET = $(TARGET_NEW_PLATFORM_NAME_REL
and then include themake/mt-os/mt-NEW_PLATFORM_NAME.mk
config file.IOTC_CONST_PLATFORM_NP4000 := <b>NEW_PLATFORM_NAME</b> ifneq (,$(findstring $(IOTC_CONST_PLATFORM_<b>NEW_PLATFORM_NAME</b>),$(TARGET))) IOTC_CONST_PLATFORM_CURRENT := $(IOTC_CONST_PLATFORM_<b>NEW_PLATFORM_NAME</b>) endif
-
Provide BSP implementations for all modules.
-
Create the following source files.
src/bsp/NEW_PLATFORM_NAME/iotc_bsp_io_fs_NEW_PLATFORM_NAME.c
src/bsp/NEW_PLATFORM_NAME/iotc_bsp_io_net_NEW_PLATFORM_NAME.c
src/bsp/NEW_PLATFORM_NAME/iotc_bsp_mem_NEW_PLATFORM_NAME.c
src/bsp/NEW_PLATFORM_NAME/iotc_bsp_rng_NEW_PLATFORM_NAME.c
src/bsp/NEW_PLATFORM_NAME/iotc_bsp_time_NEW_PLATFORM_NAME.c
-
In each these source files, define the functions declared in the corresponding Device SDK BSP headers.
- File storage:
include/bsp/iotc_bsp_io_fs.h
- Networking:
include/bsp/iotc_bsp_io_net.h
- Memory allocation:
include/bsp/iotc_bsp_mem.h
- Time:
include/bsp/iotc_bsp_time.h
- Random number generation:
include/bsp/iotc_bsp_rng.h
- File storage:
-
-
Select a TLS implementation.
-
The default library is
mbedTLS
. -
To select the
wolfSSL
library, execute the following command.make PRESET=NEW_PLATFORM_NAME IOTC_BSP_TLS=wolfSSL
-
-
To use a custom TLS implementation, execute the following command.
make PRESET=NEW_PLATFORM_NAME IOTC_BSP_TLS=NEW_TLS_LIBRARY_NAME
-
For more information on custom TLS implementations, see Custom TLS BSP.
- Build the device SDK for the new platform.
make PRESET=NEW_PLATFORM_NAME
After linking the libraries to a new platform, the BSP is customized to your device and the porting process is complete.
Try the suggestions in this section to debug issues.
The MAKEFILE_DEBUG
variable logs makefile variables to the console. You can compare the logs for your own build configuration with the logs for a POSIX default build.
To run this command with your own build configuration:
make PRESET=NEW_PLATFORM_NAME MAKEFILE_DEBUG=1
To run it for a POSIX default build:
make MAKEFILE_DEUBG=1
The following command removes local .o
, .d
or .lib
files generated during the previous make
step.
make PRESET=NEW_PLATFORM_NAME clean
We recommend cleaning your build when creating one from scratch.
The following command logs the commands that make
would execute. It only logs the commands; it doesn't execute them.
make PRESET=NEW_PLATFORM_NAME -n
Then, you can manually run each make
command in the output to determine the part of the build process that's causing an issue.
For more information about the Device SDK, see these other documents in the GitHub repository:
-
README.md
provides general information about the file structure of the source, how to build on Linux, and a general overview of security. -
doc/user_guide.md
provides an in-depth description of the Device SDK design and features, including MQTT logic, the event system, backoff logic, and platform security requirements. -
doc/doxygen/api
contains the function specifications for the Device SDK application-level API. -
doc/doxygen/bsp
contains the declarations and documentation for the abstracted Board Support Package (BSP) functions to port the Device SDK to new platforms.