summaryrefslogtreecommitdiffstats
path: root/examples/native
diff options
context:
space:
mode:
Diffstat (limited to 'examples/native')
-rw-r--r--examples/native/.gitignore3
-rwxr-xr-xexamples/native/AGLBuild.mk41
-rw-r--r--examples/native/CMakeLists.txt55
-rw-r--r--examples/native/etc/config.cmake91
-rw-r--r--examples/native/etc/export.map1
-rw-r--r--examples/native/etc/macros.cmake259
-rw-r--r--examples/native/packaging/wgt/config.xml.in11
-rw-r--r--examples/native/packaging/wgt/icon.png.inbin0 -> 5276 bytes
-rw-r--r--examples/native/xxxxxx-native-client.c242
9 files changed, 703 insertions, 0 deletions
diff --git a/examples/native/.gitignore b/examples/native/.gitignore
new file mode 100644
index 0000000..9a13971
--- /dev/null
+++ b/examples/native/.gitignore
@@ -0,0 +1,3 @@
+build
+config.xml
+*.wgt
diff --git a/examples/native/AGLBuild.mk b/examples/native/AGLBuild.mk
new file mode 100755
index 0000000..ccbc28b
--- /dev/null
+++ b/examples/native/AGLBuild.mk
@@ -0,0 +1,41 @@
+#!/usr/bin/make -f
+# Copyright (C) 2015, 2016 "IoT.bzh"
+# Author "Romain Forlot" <romain.forlot@iot.bzh>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+BUILD_DIR := build
+PACKAGING_DIR := packaging/wgt
+
+VPATH = etc:$(PACKAGING_DIR):$(PACKAGING_DIR)/etc:$(BUILD_DIR)
+
+.PHONY: all clean mrproper package
+
+all: build
+
+clean:
+ @([ -d ${BUILD_DIR} ] && make -C ${BUILD_DIR} clean) || echo Nothing to clean
+
+mrproper:
+ rm -rf ${BUILD_DIR}
+
+build: ${BUILD_DIR}/Makefile
+ cmake --build ${BUILD_DIR} --target all
+
+package: config.xml.in icon.png.in build | $(PKG_FILELIST)
+ mkdir -p ${BUILD_DIR}/$@/{bin,etc,lib,htdocs,data}
+ cmake --build ${BUILD_DIR} --target widget
+
+${BUILD_DIR}/Makefile:
+ @[ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR}
+ @[ -f ${BUILD_DIR}/Makefile ] || (cd ${BUILD_DIR} && cmake ${CMAKE_OPTS} ..) \ No newline at end of file
diff --git a/examples/native/CMakeLists.txt b/examples/native/CMakeLists.txt
new file mode 100644
index 0000000..e7ae126
--- /dev/null
+++ b/examples/native/CMakeLists.txt
@@ -0,0 +1,55 @@
+###########################################################################
+# Copyright 2015, 2016, 2017 IoT.bzh
+#
+# author: Romain Forlot <romain.forlot@iot.bzh>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+###########################################################################
+
+CMAKE_MINIMUM_REQUIRED(VERSION 3.3)
+
+include(${CMAKE_CURRENT_SOURCE_DIR}/etc/config.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/etc/macros.cmake)
+
+# Add target to project dependency list
+PROJECT_TARGET_ADD(native-example)
+
+ # Define project Targets
+ add_executable(${TARGET_NAME} xxxxxx-native-client.c
+ )
+
+ link_libraries(
+ ${CMAKE_THREAD_LIBS_INIT}
+ ${libafbwsc_LIBRARIES}
+ ${json-c_LIBRARIES}
+ ${libsystemd_LIBRARIES}
+ )
+
+ # Binder exposes a unique public entry point
+ SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES
+ PREFIX ""
+ LABELS "EXECUTABLE"
+ OUTPUT_NAME ${TARGET_NAME})
+
+ TARGET_INCLUDE_DIRECTORIES(${TARGET_NAME}
+ PUBLIC ${libafbwsc_INCLUDE_DIRS}
+ ${json-c_INCLUDE_DIRS}
+ ${libsystemd_INCLUDE_DIRS})
+
+ TARGET_LINK_LIBRARIES(${TARGET_NAME}
+ afbwsc
+ ${link_libraries})
+
+populate_widget()
+
+build_widget()
diff --git a/examples/native/etc/config.cmake b/examples/native/etc/config.cmake
new file mode 100644
index 0000000..5e8a488
--- /dev/null
+++ b/examples/native/etc/config.cmake
@@ -0,0 +1,91 @@
+###########################################################################
+# Copyright 2015, 2016, 2017 IoT.bzh
+#
+# author: Fulup Ar Foll <fulup@iot.bzh>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+###########################################################################
+
+# Project Info
+# ------------------
+set(NAME Hybrid-QML-example)
+set(VERSION "0.0")
+set(PROJECT_PRETTY_NAME "Hybrid QML Example")
+set(PROJECT_DESCRIPTION "Hybrid QML AGL application example")
+set(PROJECT_URL "https://gerrit.automotivelinux.org/gerrit/apps/app-templates")
+set(PROJECT_ICON "icon.png")
+
+# Compilation Mode (DEBUG, RELEASE)
+# ----------------------------------
+set(CMAKE_BUILD_TYPE "DEBUG")
+
+# Compiler selection if needed. Overload the detected compiler.
+# -----------------------------------------------
+#set(CMAKE_C_COMPILER "gcc")
+#set(CMAKE_CXX_COMPILER "g++")
+
+# PKG_CONFIG required packages
+# -----------------------------
+set (PKG_REQUIRED_LIST
+ json-c
+ libsystemd
+ libafbwsc
+ afb-daemon
+)
+
+# Static constante definition
+# -----------------------------
+add_compile_options(
+ ${libafbwsc_CFLAGS}
+ ${json-c_CFLAGS}
+ ${libsystemd_CFLAGS}
+)
+
+# LANG Specific compile flags set for all build types
+set(CMAKE_C_FLAGS "")
+set(CMAKE_CXX_FLAGS "")
+
+# Print a helper message when every thing is finished
+# ----------------------------------------------------
+#set(CLOSING_MESSAGE "")
+
+
+# (BUG!!!) as PKG_CONFIG_PATH does not work [should be an env variable]
+# ---------------------------------------------------------------------
+set(CMAKE_INSTALL_PREFIX ${HOME}/opt)
+set(CMAKE_PREFIX_PATH ${CMAKE_INSTALL_PREFIX}/lib64/pkgconfig ${CMAKE_INSTALL_PREFIX}/lib/pkgconfig)
+set(LD_LIBRARY_PATH ${CMAKE_INSTALL_PREFIX}/lib64 ${CMAKE_INSTALL_PREFIX}/lib)
+
+# Optional dependencies order
+# ---------------------------
+#set(EXTRA_DEPENDENCIES_ORDER)
+
+# Optional Extra global include path
+# -----------------------------------
+#set(EXTRA_INCLUDE_DIRS)
+
+# Optional extra libraries
+# -------------------------
+#set(EXTRA_LINK_LIBRARIES)
+
+# Optional force binding installation
+# ------------------------------------
+set(BINDINGS_INSTALL_PREFIX /opt )
+
+# Optional force widget prefix generation
+# ---------------------------------------
+# set(WIDGET_PREFIX DestinationPath)
+
+# Optional force binding Linking flag
+# ------------------------------------
+# set(BINDINGS_LINK_FLAG LinkOptions )
diff --git a/examples/native/etc/export.map b/examples/native/etc/export.map
new file mode 100644
index 0000000..52c1b4a
--- /dev/null
+++ b/examples/native/etc/export.map
@@ -0,0 +1 @@
+{ global: afbBindingV1*; local: *; };
diff --git a/examples/native/etc/macros.cmake b/examples/native/etc/macros.cmake
new file mode 100644
index 0000000..1b9625c
--- /dev/null
+++ b/examples/native/etc/macros.cmake
@@ -0,0 +1,259 @@
+###########################################################################
+# Copyright 2015, 2016, 2017 IoT.bzh
+#
+# author: Fulup Ar Foll <fulup@iot.bzh>
+# contrib: Romain Forlot <romain.forlot@iot.bzh>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+###########################################################################
+
+
+#--------------------------------------------------------------------------
+# WARNING:
+# Do not change this cmake template
+# Customise your preferences in "./etc/config.cmake"
+#--------------------------------------------------------------------------
+
+
+# Generic useful macro
+# -----------------------
+macro(PROJECT_TARGET_ADD TARGET_NAME)
+ set(PROJECT_TARGETS ${PROJECT_TARGETS} ${TARGET_NAME} CACHE INTERNAL PROJECT_TARGETS)
+ set(TARGET_NAME ${TARGET_NAME})
+endmacro(PROJECT_TARGET_ADD)
+
+macro(defstr name value)
+ add_definitions(-D${name}=${value})
+endmacro(defstr)
+
+macro(setc name value)
+ if(NOT DEFINED ${name})
+ set(${name} ${value})
+ endif(NOT DEFINED ${name})
+endmacro(setc)
+
+# Dumb macro to add each directory under a path. Make sure we grab all header files!
+macro(fill_include_dir path)
+ file(GLOB_RECURSE dirlist LIST_DIRECTORIES true "${path}/*")
+ foreach(filename ${dirlist})
+ if(IS_DIRECTORY ${filename})
+ include_directories(${filename})
+ endif(IS_DIRECTORY ${filename})
+ endforeach()
+endmacro(fill_include_dir)
+
+# Helper function to retrieve source files from a library repo.
+function(find_source_files path)
+ file(GLOB_RECURSE cfiles "${path}/*.[c]")
+ file(GLOB_RECURSE cppfiles "${path}/*.cpp")
+ foreach(filename ${cfiles})
+ if(NOT ${filename} MATCHES ".*([Tt]est|[Ee]xample|[Ss]ample).*")
+ string(APPEND sources "${filename};")
+ endif(NOT ${filename} MATCHES ".*([Tt]est|[Ee]xample|[Ss]ample).*")
+ endforeach()
+ foreach(filename ${cppfiles})
+ if(NOT ${filename} MATCHES ".*([Tt]est|[Ee]xample|[Ss]ample).*")
+ string(APPEND sources "${filename};")
+ endif(NOT ${filename} MATCHES ".*([Tt]est|[Ee]xample|[Ss]ample).*")
+ endforeach()
+ set(sources_files ${sources} PARENT_SCOPE)
+endfunction(find_source_files)
+
+# WGT packaging
+macro(populate_widget)
+ # Declaration of a custom command that will populate widget tree with the target
+ set(POPULE_WIDGET_TARGET "populate_${TARGET_NAME}")
+
+ get_target_property(T ${TARGET_NAME} LABELS)
+ if(${T} STREQUAL "BINDING")
+ add_custom_command(OUTPUT ${WIDGET_LIBDIR}/${TARGET_NAME}.so
+ DEPENDS ${TARGET_NAME}
+ COMMAND mkdir -p ${WIDGET_LIBDIR}
+ COMMAND cp ${TARGET_NAME}.so ${WIDGET_LIBDIR}
+ )
+ add_custom_target(${POPULE_WIDGET_TARGET} ALL DEPENDS ${WIDGET_LIBDIR}/${TARGET_NAME}.so)
+ elseif(${T} STREQUAL "EXECUTABLE")
+ get_target_property(OUT ${TARGET_NAME} OUTPUT_NAME)
+ add_custom_command(OUTPUT ${WIDGET_BINDIR}/${TARGET_NAME}
+ DEPENDS ${TARGET_NAME}
+ COMMAND mkdir -p ${WIDGET_BINDIR}
+ COMMAND cp ${OUT} ${WIDGET_BINDIR}
+ )
+ add_custom_target(${POPULE_WIDGET_TARGET} ALL DEPENDS ${WIDGET_BINDIR}/${TARGET_NAME})
+ elseif(${T} STREQUAL "HTDOCS")
+ get_target_property(OUT ${TARGET_NAME} OUTPUT_NAME)
+ add_custom_command(OUTPUT ${WIDGET_HTTPDIR}
+ DEPENDS ${TARGET_NAME}
+ COMMAND cp -r ${OUT} ${WIDGET_HTTPDIR}
+ )
+ add_custom_target(${POPULE_WIDGET_TARGET} ALL DEPENDS ${WIDGET_HTTPDIR})
+ elseif(${T} STREQUAL "DATA")
+ get_target_property(OUT ${TARGET_NAME} OUTPUT_NAME)
+ add_custom_command(OUTPUT ${WIDGET_DATADIR}
+ DEPENDS ${TARGET_NAME}
+ COMMAND cp -r ${OUT} ${WIDGET_DATADIR}
+ )
+ add_custom_target(${POPULE_WIDGET_TARGET} ALL DEPENDS ${WIDGET_HTTPDIR})
+ endif(${T} STREQUAL "BINDING")
+ PROJECT_TARGET_ADD(${POPULE_WIDGET_TARGET})
+endmacro(populate_widget)
+
+macro(build_widget)
+ if("${PROJECT_TARGETS}" MATCHES "populate_")
+ if(NOT EXISTS ${WIDGET_DIR}/config.xml.in OR NOT EXISTS ${WIDGET_DIR}/${PROJECT_ICON}.in)
+ configure_file(${PROJECT_WGT_DIR}/config.xml.in ${WIDGET_DIR}/config.xml)
+ file(COPY ${PROJECT_WGT_DIR}/${PROJECT_ICON}.in DESTINATION ${WIDGET_DIR}/${PROJECT_ICON})
+ endif(NOT EXISTS ${WIDGET_DIR}/config.xml.in OR NOT EXISTS ${WIDGET_DIR}/${PROJECT_ICON}.in)
+
+ file(GLOB PROJECT_CONF_FILES "${PROJECT_WGT_DIR}/etc/*")
+ if(${PROJECT_CONF_FILES})
+ file(COPY "${PROJECT_WGT_DIR}/etc/*" DESTINATION ${WIDGET_ETCDIR}/)
+ endif(${PROJECT_CONF_FILES})
+
+ add_custom_command(OUTPUT ${PROJECT_NAME}.wgt
+ DEPENDS ${PROJECT_TARGETS}
+ COMMAND wgtpkg-pack -f -o ${PROJECT_NAME}.wgt ${WIDGET_DIR}
+ )
+ add_custom_target(widget DEPENDS ${PROJECT_NAME}.wgt)
+ else()
+ MESSAGE(FATAL_ERROR "Widget tree empty, please populate it by calling populate_widget() macro with target you want to include into it.")
+ endif("${PROJECT_TARGETS}" MATCHES "populate_")
+endmacro(build_widget)
+
+macro(search_targets)
+ file(GLOB filelist "*")
+ foreach(filename ${filelist})
+ if(EXISTS "${filename}/CMakeLists.txt")
+ add_subdirectory(${filename})
+ endif(EXISTS "${filename}/CMakeLists.txt")
+ endforeach()
+endmacro()
+
+setc(CMAKE_BUILD_TYPE Debug)
+set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+set(CMP0048 1)
+
+# Include project configuration
+# ------------------------------
+project(${NAME} VERSION ${VERSION})
+setc(PROJECT_WGT_DIR "packaging/wgt")
+setc(PROJECT_LIBDIR "libs")
+setc(PROJECT_RESOURCES "data")
+
+INCLUDE(FindPkgConfig)
+INCLUDE(CheckIncludeFiles)
+INCLUDE(CheckLibraryExists)
+INCLUDE(GNUInstallDirs)
+
+# Default compilation options
+############################################################################
+link_libraries(-Wl,--as-needed -Wl,--gc-sections)
+add_compile_options(-Wall -Wextra -Wconversion)
+add_compile_options(-Wno-unused-parameter) # frankly not using a parameter does it care?
+add_compile_options(-Wno-sign-compare -Wno-sign-conversion)
+add_compile_options(-Werror=maybe-uninitialized)
+add_compile_options(-Werror=implicit-function-declaration)
+add_compile_options(-ffunction-sections -fdata-sections)
+add_compile_options(-fPIC)
+add_compile_options(-g)
+
+setc(CMAKE_C_FLAGS_PROFILING "-g -O2 -pg -Wp,-U_FORTIFY_SOURCE")
+setc(CMAKE_C_FLAGS_DEBUG "-g -O2 -ggdb -Wp,-U_FORTIFY_SOURCE")
+setc(CMAKE_C_FLAGS_RELEASE "-O2")
+setc(CMAKE_C_FLAGS_CCOV "-g -O2 --coverage")
+
+set(CMAKE_CXX_FLAGS_PROFILING "-g -O0 -pg -Wp,-U_FORTIFY_SOURCE")
+set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -ggdb -Wp,-U_FORTIFY_SOURCE")
+set(CMAKE_CXX_FLAGS_RELEASE "-g -O2")
+set(CMAKE_CXX_FLAGS_CCOV "-g -O2 --coverage")
+
+setc(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/Install")
+
+# (BUG!!!) as PKG_CONFIG_PATH does not work [should be en env variable]
+setc(PKG_CONFIG_USE_CMAKE_PREFIX_PATH 1)
+
+# Loop on required package and add options
+foreach (PKG_CONFIG ${PKG_REQUIRED_LIST})
+ PKG_CHECK_MODULES(${PKG_CONFIG} REQUIRED ${PKG_CONFIG})
+
+ INCLUDE_DIRECTORIES(${${PKG_CONFIG}_INCLUDE_DIRS})
+ list (APPEND link_libraries ${${PKG_CONFIG}_LIBRARIES})
+ add_compile_options (${${PKG_CONFIG}_CFLAGS})
+endforeach(PKG_CONFIG)
+
+# Optional LibEfence Malloc debug library
+IF(CMAKE_BUILD_TYPE MATCHES DEBUG)
+CHECK_LIBRARY_EXISTS(efence malloc "" HAVE_LIBEFENCE)
+IF(HAVE_LIBEFENCE)
+ MESSAGE(STATUS "Linking with ElectricFence for debugging purposes...")
+ SET(libefence_LIBRARIES "-lefence")
+ list (APPEND link_libraries libefence_LIBRARIES})
+ENDIF(HAVE_LIBEFENCE)
+ENDIF(CMAKE_BUILD_TYPE MATCHES DEBUG)
+
+# set default include directories
+INCLUDE_DIRECTORIES(${EXTRA_INCLUDE_DIRS})
+
+# If no install dir try to guess some smart default
+if(BINDINGS_INSTALL_PREFIX)
+ set(BINDINGS_INSTALL_DIR ${BINDINGS_INSTALL_PREFIX}/${PROJECT_NAME})
+else()
+ set(BINDINGS_INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME})
+endif()
+
+# Define a default package directory
+if(WIDGET_PREFIX)
+ set(WIDGET_DIR ${WIDGET_PREFIX}/package)
+else()
+ set(WIDGET_DIR ${CMAKE_CURRENT_BINARY_DIR}/package)
+endif()
+
+# and their subsequent subdir
+set(WIDGET_BINDIR ${WIDGET_DIR}/bin)
+set(WIDGET_ETCDIR ${WIDGET_DIR}/etc)
+set(WIDGET_LIBDIR ${WIDGET_DIR}/lib)
+set(WIDGET_HTTPDIR ${WIDGET_DIR}/htdocs)
+set(WIDGET_DATADIR ${WIDGET_DIR}/data)
+
+# Default Linkflag
+if(NOT BINDINGS_LINK_FLAG)
+ set(BINDINGS_LINK_FLAG "-Wl,--version-script=${CMAKE_SOURCE_DIR}/etc/export.map")
+endif()
+
+# Add a dummy target to enable global dependency order
+# -----------------------------------------------------
+if(EXTRA_DEPENDENCIES_ORDER)
+ set(DEPENDENCIES_TARGET ${PROJECT_NAME}_extra_dependencies)
+ add_custom_target(${DEPENDENCIES_TARGET} ALL
+ DEPENDS ${EXTRA_DEPENDENCY_ORDER}
+ )
+endif()
+
+# Cmake does not maintain targets list before 3.7
+# -------------------------------------------------
+if(${CMAKE_VERSION} VERSION_LESS 3.7)
+ set(GLOBAL_TARGET_LIST ${PROJECT_TARGETS})
+else()
+ get_property(GLOBAL_TARGET_LIST GLOBAL PROPERTY GlobalTargetList)
+endif()
+
+# Print developer helper message when everything is done
+# -------------------------------------------------------
+if(CLOSING_MESSAGE AND GLOBAL_TARGET_LIST)
+ add_custom_target(${PROJECT_NAME}_done ALL
+ DEPENDS ${DEPENDENCIES_TARGET} ${GLOBAL_TARGET_LIST}
+ COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --cyan "++ ${CLOSING_MESSAGE}"
+ )
+endif()
+
+set(ADDITIONAL_MAKE_CLEAN_FILES, "low-can-binding/low-can-binding.wgt")
diff --git a/examples/native/packaging/wgt/config.xml.in b/examples/native/packaging/wgt/config.xml.in
new file mode 100644
index 0000000..99c0168
--- /dev/null
+++ b/examples/native/packaging/wgt/config.xml.in
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<widget xmlns="http://www.w3.org/ns/widgets" id="@PROJECT_NAME@" version="@PROJECT_VERSION@">
+ <name>@PROJECT_NAME@</name>
+ <icon src="icon.png"/>
+ <content src="htdocs/index.html" type="application/vnd.agl.html.hybrid"/>
+ <description>@PROJECT_DESCRIPTION@</description>
+ <author>Romain Forlot &lt;romain.forlot@iot.bzh&gt;</author>
+ <license>APL 2.0</license>
+</widget>
+
+
diff --git a/examples/native/packaging/wgt/icon.png.in b/examples/native/packaging/wgt/icon.png.in
new file mode 100644
index 0000000..fcb5d35
--- /dev/null
+++ b/examples/native/packaging/wgt/icon.png.in
Binary files differ
diff --git a/examples/native/xxxxxx-native-client.c b/examples/native/xxxxxx-native-client.c
new file mode 100644
index 0000000..312fd1a
--- /dev/null
+++ b/examples/native/xxxxxx-native-client.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2015, 2016 "IoT.bzh"
+ * Author "Fulup Ar Foll" <fulup@iot.bzh>
+ * Author José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#include <systemd/sd-event.h>
+
+#include <afb/afb-wsj1.h>
+#include <afb/afb-ws-client.h>
+
+/* declaration of functions */
+static void on_hangup(void *closure, struct afb_wsj1 *wsj1);
+static void on_call(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg);
+static void on_event(void *closure, const char *event, struct afb_wsj1_msg *msg);
+static int io_event_callback(sd_event_source *src, int fd, uint32_t revents, void *closure);
+static void emit(const char *api, const char *verb, const char *object);
+
+/* the callback interface for wsj1 */
+static struct afb_wsj1_itf itf = {
+ .on_hangup = on_hangup,
+ .on_call = on_call,
+ .on_event = on_event
+};
+
+/* global variables */
+static struct afb_wsj1 *wsj1;
+static int exonrep;
+static int callcount;
+static sd_event_source *evsrc;
+
+/* print usage of the program */
+static void usage(int status, char *arg0)
+{
+ char *name = strrchr(arg0, '/');
+ name = name ? name + 1 : arg0;
+ fprintf(status ? stderr : stdout, "usage: %s uri [api verb [data]]\n", name);
+ exit(status);
+}
+
+/* entry function */
+int main(int ac, char **av, char **env)
+{
+ int rc;
+ sd_event *loop;
+
+ /* check the argument count */
+ if (ac != 2 && ac != 4 && ac != 5)
+ usage(1, av[0]);
+
+ /* emit error and exit if requested */
+ if (!strcmp(av[1], "-h") || !strcmp(av[1], "--help"))
+ usage(0, av[0]);
+
+ /* get the default event loop */
+ rc = sd_event_default(&loop);
+ if (rc < 0) {
+ fprintf(stderr, "connection to default event loop failed: %s\n", strerror(-rc));
+ return 1;
+ }
+
+ /* connect the websocket wsj1 to the uri given by the first argument */
+ wsj1 = afb_ws_client_connect_wsj1(loop,av[1], &itf, NULL);
+ if (wsj1 == NULL) {
+ fprintf(stderr, "connection to %s failed: %m\n", av[1]);
+ return 1;
+ }
+
+ /* test the behaviour */
+ if (ac == 2) {
+ /* get requests from stdin */
+ fcntl(0, F_SETFL, O_NONBLOCK);
+ sd_event_add_io(loop, &evsrc, 0, EPOLLIN, io_event_callback, NULL);
+ } else {
+ /* the request is defined by the arguments */
+ exonrep = 1;
+ emit(av[2], av[3], av[4]);
+ }
+
+ /* loop until end */
+ for(;;)
+ sd_event_run(loop, 30000000);
+ return 0;
+}
+
+/* called when wsj1 hangsup */
+static void on_hangup(void *closure, struct afb_wsj1 *wsj1)
+{
+ printf("ON-HANGUP\n");
+ exit(0);
+}
+
+/* called when wsj1 receives a method invocation */
+static void on_call(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg)
+{
+ int rc;
+ printf("ON-CALL %s/%s(%s)\n", api, verb, afb_wsj1_msg_object_s(msg));
+ rc = afb_wsj1_reply_error_s(msg, "\"unimplemented\"", NULL);
+ if (rc < 0)
+ fprintf(stderr, "replying failed: %m\n");
+}
+
+/* called when wsj1 receives an event */
+static void on_event(void *closure, const char *event, struct afb_wsj1_msg *msg)
+{
+ printf("ON-EVENT %s(%s)\n", event, afb_wsj1_msg_object_s(msg));
+}
+
+/* called when wsj1 receives a reply */
+static void on_reply(void *closure, struct afb_wsj1_msg *msg)
+{
+ printf("ON-REPLY %s: %s\n", (char*)closure, afb_wsj1_msg_object_s(msg));
+ free(closure);
+ callcount--;
+ if (exonrep && !callcount)
+ //afb_wsj1_hangup(afb_wsj1_msg_wsj1(msg));
+ exit(0);
+}
+
+/* makes a call */
+static void call(const char *api, const char *verb, const char *object)
+{
+ static int num = 0;
+ char *key;
+ int rc;
+
+ /* allocates an id for the request */
+ rc = asprintf(&key, "%d:%s/%s", ++num, api, verb);
+
+ /* send the request */
+ callcount++;
+ rc = afb_wsj1_call_s(wsj1, api, verb, object, on_reply, key);
+ if (rc < 0) {
+ fprintf(stderr, "calling %s/%s(%s) failed: %m\n", api, verb, object);
+ callcount--;
+ }
+}
+
+/* sends an event */
+static void event(const char *event, const char *object)
+{
+ int rc;
+
+ rc = afb_wsj1_send_event_s(wsj1, event, object);
+ if (rc < 0)
+ fprintf(stderr, "sending !%s(%s) failed: %m\n", event, object);
+}
+
+/* emits either a call (when api!='!') or an event */
+static void emit(const char *api, const char *verb, const char *object)
+{
+ if (object == NULL || object[0] == 0)
+ object = "null";
+ if (api[0] == '!' && api[1] == 0)
+ event(verb, object);
+ else
+ call(api, verb, object);
+}
+
+/* called when something happens on stdin */
+static int io_event_callback(sd_event_source *src, int fd, uint32_t revents, void *closure)
+{
+ static size_t count = 0;
+ static char line[16384];
+ static char sep[] = " \t";
+ static char sepnl[] = " \t\n";
+
+ ssize_t rc;
+ size_t pos;
+
+ /* read the buffer */
+ do { rc = read(0, line + count, sizeof line - count); } while (rc < 0 && errno == EINTR);
+ if (rc < 0) {
+ fprintf(stderr, "read error: %m\n");
+ exit(1);
+ }
+ if (rc == 0) {
+ if (!callcount)
+ exit(0);
+ exonrep = 1;
+ sd_event_source_unref(evsrc);
+ }
+ count += (size_t)rc;
+
+ /* normalise the buffer content */
+ /* TODO: handle backspace \x7f ? */
+
+ /* process the lines */
+ pos = 0;
+ for(;;) {
+ size_t i, api[2], verb[2], rest[2];
+ i = pos;
+ while(i < count && strchr(sep, line[i])) i++;
+ api[0] = i; while(i < count && !strchr(sepnl, line[i])) i++; api[1] = i;
+ while(i < count && strchr(sep, line[i])) i++;
+ verb[0] = i; while(i < count && !strchr(sepnl, line[i])) i++; verb[1] = i;
+ while(i < count && strchr(sep, line[i])) i++;
+ rest[0] = i; while(i < count && line[i] != '\n') i++; rest[1] = i;
+ if (i == count) break;
+ line[i++] = 0;
+ if (api[0] == api[1] || verb[0] == verb[1])
+ fprintf(stderr, "bad line: %s\n", line+pos);
+ else {
+ line[api[1]] = line[verb[1]] = 0;
+ emit(line + api[0], line + verb[0], line + rest[0]);
+ }
+ pos = i;
+ }
+ count -= pos;
+ if (count == sizeof line) {
+ fprintf(stderr, "overflow\n");
+ exit(1);
+ }
+ if (count)
+ memmove(line, line + pos, count);
+ return 1;
+}
+