Skip to content

Commit

Permalink
Merge pull request #600 from google/embedded
Browse files Browse the repository at this point in the history
Add embedded SDK
  • Loading branch information
jgsobczak committed Apr 14, 2022
2 parents 93f203d + daac1e0 commit 940dba6
Show file tree
Hide file tree
Showing 40 changed files with 7,443 additions and 0 deletions.
181 changes: 181 additions & 0 deletions embedded/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
# Makefile arguments
#
#
# Delete the default suffix rules.
.SUFFIXES:
.SECONDARY:

GTEST_DIR = ../third_party/gtest/googletest/
GMOCK_DIR = ../third_party/gtest/googlemock/

ARCH ?= host
OUT_DIR_NAME ?= $(ARCH)
OUT_DIR = out/$(OUT_DIR_NAME)
DIST_DIR = dist/$(OUT_DIR_NAME)

CFLAGS := -Wall
COMMON_INCLUDE_DIRS :=
CLIENT_INCLUDES :=
# For ARCH variants like gLinux_hw set to gLinux.
ARCH_COMMON_NAME := $(ARCH)
ARCH_COMMON_DIR = common/source/$(ARCH_COMMON_NAME)
CLIENT_DIR = client/source
CLIENT_SRCS :=

NEARBY_LIB_NAME = libnearby.a

NAME = $(OUT_DIR)/$(NEARBY_LIB_NAME)

all : $(NAME)

COMMON_DIR = common/source
COMMON_C_FILES :=

# All output objects for the build system should be added to ALL_OBJS.
ALL_OBJS :=
# Extra dependencies of the dist target.
DIST_LIST :=

# Name of the libnearby static library that we distribute.
DIST_NEARBY_LIB_NAME ?= $(DIST_DIR)/$(NEARBY_LIB_NAME)

# Kokoro on Windows is wonky. We can't shell out to git because we are in
# cygwin, so this is pre-computed by continuous.bat
ifneq ($(FIRMWARE_VERSION_FILENAME),)
FIRMWARE_VERSION := $(shell cat $(FIRMWARE_VERSION_FILENAME))
else
FIRMWARE_VERSION_FILENAME = $(OUT_DIR)/FIRMWARE_VERSION
PHONY_VERSION_FILENAME = $(OUT_DIR)/PHONY_FIRMWARE_VERSION
FIRMWARE_VERSION := $(shell git -c core.fileMode=false describe --always --dirty --exclude="*")
FIRMWARE_VERSION_FILENAME: $(PHONY_VERSION_FILENAME)

ifneq ($(KOKORO_RELEASE_BUILD),1)
FIRMWARE_VERSION := $(FIRMWARE_VERSION)ENG
endif

# Update the phony version on every build.
.PHONY: $(PHONY_VERSION_FILENAME)
$(PHONY_VERSION_FILENAME):
@mkdir -p $(dir $@) ;\
echo $(FIRMWARE_VERSION) > $@ ;\

# Only update this version if necessary (if it's different from the phony). This
# tricks make into not updating dependencies of FIRMWARE_VERSION_FILENAME unless
# the file is updated. .PHONY is not transitive.
$(FIRMWARE_VERSION_FILENAME): $(PHONY_VERSION_FILENAME)
@cmp $@ $< 2>> /dev/null || cp -v $< $@

endif

# Note $(notdir) below converts a path to just the base file name
define compile_c
mkdir -p $(dir $@)
$(CC) -c $(1) -o $@ -D__NEARBY_SHORT_FILE__='"$(notdir $<)"' $<
endef

# Include all of the target specific variables and rules.
# The $(ARCH).mk files should only depend on the variables listed above.
include target/$(ARCH)/config.mk

# Set trace verbosity from target specific variable
CFLAGS += -DNEARBY_TRACE_LEVEL=NEARBY_TRACE_LEVEL_$(NEARBY_TRACE_LEVEL)
# if directory doesn't exist, raise an error so we don't fail later with more cryptic warnings
ifeq ($(wildcard common/target/$(ARCH_COMMON_NAME)),)
$(error need to create directory common/target/$(ARCH_COMMON_NAME) )
endif

COMMON_INCLUDE_DIRS += \
-I. \
-I$(ARCH_COMMON_DIR) \
-Icommon/target \
-Icommon/target/$(ARCH_COMMON_NAME) \
-I$(COMMON_DIR)

CLIENT_INCLUDES += \
-I$(CLIENT_DIR) \
-Iclient/target

COMMON_C_FILES += \
$(wildcard $(COMMON_DIR)/*.c)

CLIENT_SRCS += \
$(wildcard $(CLIENT_DIR)/*.c)

CFLAGS += $(COMMON_INCLUDE_DIRS)

CROSS_COMPILE ?= arm-none-eabi-
CC ?= $(CROSS_COMPILE)gcc
AR ?= $(CROSS_COMPILE)ar
ALL_C_FILES = $(COMMON_C_FILES)
COMMON_OBJS = $(patsubst %.c,$(OUT_DIR)/%.o,$(ALL_C_FILES))
CLIENT_OBJS = $(patsubst %.c,$(OUT_DIR)/%.o,$(CLIENT_SRCS))
NEARBY_LIB_OBJS = $(COMMON_OBJS) $(CLIENT_OBJS)

NEARBY_HEADERS += $(patsubst common/target/%.h,$(DIST_DIR)/%.h,$(wildcard common/target/*.h))
NEARBY_HEADERS += $(patsubst common/target/$(ARCH_COMMON_NAME)/%.h,$(DIST_DIR)/%.h,$(wildcard common/target/$(ARCH_COMMON_NAME)/*.h))
NEARBY_HEADERS += $(patsubst client/target/%,$(DIST_DIR)/%,$(wildcard client/target/*.h))

NEARBY_DIST_HEADERS := $(NEARBY_HEADERS)

DIST_LIST += $(NEARBY_DIST_HEADERS)
DIST_LIST += $(DIST_NEARBY_LIB_NAME)

$(DIST_DIR)/nearby.h: $(FIRMWARE_VERSION_FILENAME)
$(DIST_DIR)/nearby.h: common/target/nearby.h
@mkdir -p $(dir $@)
$(call copy_dist_header)
sed -i -e "s/\(define\s*NEARBY_BUILD_ID\).*/\1 \"$(FIRMWARE_VERSION)\"/" $@

define copy_dist_header
@mkdir -p $(dir $@)
@test "$$(head -n 2 $< | grep 'Copyright [0-9]\{4\} Google LLC.')" != "" || \
(echo ; echo "=====ERROR=====" ; echo "Missing copyright in $<" ; exit 1)
unifdef -t -b -x2 $(UNIFDEF_ARG) -o - $< | cat - >$@
@# (mkartoz) Should be able to specify $@ as the output directly from
@# unifdef but, if you do that, the file never shows up on kokoro. Piping to
@# cat is a workaround.
endef

# Do not bypass the whole build process if the dist directory exists
.PHONY: dist
dist : all \
$(DIST_LIST)

$(DIST_DIR)/$(NEARBY_LIB_NAME) : $(NAME)
mkdir -p $(dir $@)
cp -uv $< $@

$(DIST_DIR)/%.h : common/target/%.h
$(call copy_dist_header)

$(DIST_DIR)/%.h : common/target/$(ARCH_COMMON_NAME)/%.h
$(call copy_dist_header)

$(NAME): $(NEARBY_LIB_OBJS)
mkdir -p $(dir $@)
$(AR) rcs $@ $(NEARBY_LIB_OBJS)

# If the hash has changed then we need to rebuild nearby.o and nearby_client.o
$(filter %/nearby_client.o, $(NEARBY_LIB_OBJS)): $(FIRMWARE_VERSION_FILENAME)
$(filter %/nearby.o, $(NEARBY_LIB_OBJS)): $(FIRMWARE_VERSION_FILENAME)

$(CLIENT_OBJS) : $(OUT_DIR)/%.o : %.c
$(call compile_c, $(CFLAGS) -Icommon/target $(CLIENT_INCLUDES))

$(COMMON_OBJS) : $(OUT_DIR)/%.o: %.c
$(call compile_c,$(CFLAGS))

ALL_OBJS += $(NEARBY_LIB_OBJS) $(CLIENT_OBJS)

DEPFILES = $(ALL_OBJS:.o=.d)

-include $(DEPFILES)

.PHONY: clean
clean:
rm -f $(NAME)
rm -f $(ALL_OBJS) $(DEPFILES)
rm -f $(FIRMWARE_VERSION_FILENAME) $(PHONY_VERSION_FILENAME)
rm -f $(DIST_LIST) $(TEST_BINARIES)

-include target/$(ARCH)/rules.mk
31 changes: 31 additions & 0 deletions embedded/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Nearby embedded SDK library

This repository contains Nearby SDK library for embedded systems. Nearby SDK
implements the Fast Pair protocol and its future versions per
https://developers.google.com/nearby/fast-pair/spec


## Threading model

Nearby SDK assumes a single-threading model. All calls to the SDK must be on the same thread, or protected with a mutex. That includes:
- client API, for example `nearby_fp_client_SetAdvertisement()`
- ble and other event callbacks
- timers

## Porting guidelines

1. Follow the steps at [Fast Pair Help](https://developers.google.com/nearby/fast-pair/help) to
register a Model Id for your device.
1. Review `nearby_config.h` and disable features, if any, that you don't
wish to support.
1. Implement the HAL defined in `nearby_platform_*.h` headers.
1. Set platform specific compile flags in `config.mk` - see
`target/gLinux/config.mk` for inspiration, and add your platform in
`build.sh`, or use your own build system.
1. Compile with `./build.sh <your platform>`
1. Start advertising in your application. For example
```
nearby_fp_client_Init(NULL);
nearby_fp_client_SetAdvertisement(NEARBY_FP_ADVERTISEMENT_DISCOVERABLE);
```
1. Use [Fast Pair Validator](https://play.google.com/store/apps/details?id=com.google.location.nearby.apps.fastpair.validator) to verify that your device is behaving correctly.
83 changes: 83 additions & 0 deletions embedded/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#!/bin/sh
#
# Parameters:
# ${1} architecture (default: gLinux)
# ${2} make target (e.g. "dist")
# (remaining params are also passed to make)
#
# Checks for environment variables:
# NEARBY_MAKEFILE_DEBUG: if set, passes -d argument to make
# many others, not fully documented here yet
#
# e.g.
# ./build.sh gLinux dist DEBUG=1

if [ "${1}" == "help" ] ; then
echo "Usage:"
echo " ./build.sh <target> [dist] [args]"
echo ""
echo "Optional arguments:"
echo " DEBUG=1"
echo " -j72 # parallelizes build using 72 cores"
exit -1;
fi

if [ "${1}" != "" ] ; then
ARCH="${1}"
shift 1
else
ARCH=gLinux
fi

CC=arm-none-eabi-gcc
AR=arm-none-eabi-ar

UNAME_OUT="$(uname -s)"
case "${UNAME_OUT}" in
Linux*) MACHINE=linux;;
Darwin*) MACHINE=mac;;
CYGWIN*) MACHINE=cygwin;;
MINGW*) MACHINE=mingw;;
*) MACHINE=windows;;
esac

if [ "${ARCH}" = "gLinux" ] ; then
if [ -x /usr/bin/clang ] ; then
CC=clang
else
CC=clang-3.8
fi
AR=ar
else
echo "Invalid target specified on command line ${ARCH}"
exit 1
fi

export NEARBY=$(cd `dirname ${0}` && pwd)

PLATFORM=$(uname -s | grep -i '\(mingw\|cygwin\)')
echo $PLATFORM

make_args=
if [ ! -z "$NEARBY_MAKEFILE_DEBUG" ]; then
echo "NEARBY_MAKEFILE_DEBUG is set, passing -d to make"
make_args+=" -d"
fi

make \
$make_args \
-C "${NEARBY}" \
CC="${CC}" \
AR="${AR}" \
ARCH="${ARCH}" \
$@

make_rc=$?

# NOTE: if make fails, it is important that the bad return code is bubbled up
# to the caller of this script.
# We don't want automated processes to keep going if there was a build error.

if [ $make_rc -ne 0 ]; then
exit $make_rc
fi
Loading

0 comments on commit 940dba6

Please sign in to comment.