diff options
-rw-r--r-- | .gitignore | 12 | ||||
-rw-r--r-- | .gitmodules | 3 | ||||
-rw-r--r-- | CMakeLists.txt | 3 | ||||
-rw-r--r-- | LICENSE | 21 | ||||
-rw-r--r-- | README.md | 140 | ||||
-rw-r--r-- | Vagrantfile | 50 | ||||
-rw-r--r-- | agl-speech-afb/CMakeLists.txt | 36 | ||||
-rw-r--r-- | agl-speech-afb/agl-speech-binding.c | 289 | ||||
m--------- | conf.d/app-templates | 0 | ||||
-rwxr-xr-x | conf.d/autobuild/agl/autobuild | 67 | ||||
-rwxr-xr-x | conf.d/autobuild/linux/autobuild | 67 | ||||
-rw-r--r-- | conf.d/cmake/config.cmake | 184 | ||||
-rw-r--r-- | conf.d/packaging/agl-helloworld-service.dsc | 18 | ||||
-rw-r--r-- | conf.d/packaging/agl-helloworld-service.spec | 66 | ||||
-rw-r--r-- | conf.d/packaging/debian.agl-helloworld-service.install | 2 | ||||
-rw-r--r-- | conf.d/packaging/debian.changelog | 5 | ||||
-rw-r--r-- | conf.d/packaging/debian.compat | 1 | ||||
-rw-r--r-- | conf.d/packaging/debian.control | 19 | ||||
-rw-r--r-- | conf.d/packaging/debian.rules | 87 | ||||
-rw-r--r-- | conf.d/wgt/config.xml.in | 15 |
20 files changed, 1085 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..126c55e --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +**/*.log
+**/.vagrant
+
+build*
+package
+nbproject/private
+.stfolder
+.*.sw*
+*.tar.gz
+.vscode
+__*
+
diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..e07cae1 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "conf.d/app-templates"] + path = conf.d/app-templates + url = https://gerrit.automotivelinux.org/gerrit/p/apps/app-templates.git diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..f757721 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,3 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 3.3) + +include(${CMAKE_CURRENT_SOURCE_DIR}/conf.d/cmake/config.cmake) @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Nuance Communications + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..9d10abb --- /dev/null +++ b/README.md @@ -0,0 +1,140 @@ +# AGL Speech interface draft
+
+This is a draft interface proposal for the low-level [Automotive Grade Linux](https://www.automotivelinux.org/) speech interface that is currently being discussed in the speech expert group.
+The interface encapsulates proprietary speech interfaces and contains both speech input (speech recognition, natural language understanding (NLU)) as well as speech output for multiple languages.
+The speech output contains an interface to play a "prompt", i.e. an arbitrary string to be synthesized into audio. It can optionally contain SSML markup to control the speech synthesis (e.g. volume, rate, embedded audio files, ...). The engine sends events when the prompt playback starts and when it finishes.
+The speech input is extremely simplified in this version and is reduced to the event that is raised when an "intent" was recognized. Intents are similar to commands and can be routed to the appropriate AGL application by a higher layer. The current interface proposal does not comprise specification of intents via grammars or NLU models.
+
+This project contains a mock implementation of the speech interface, e.g. when you play a prompt, it raises the events with a certain delay, and when you start the speech recognition, it will send an event with an example phrase after a few seconds. There's no actual interaction with a TTS or speech recognition engine.
+
+# How to build
+
+To build, you can use the provided [Vagrant](https://www.vagrantup.com/) file. Alternatively, you can use any machine with Ubuntu 16.04 and execute the shell commands in Vagrantfile.
+
+Create the VM with
+```
+vagrant up
+```
+
+Then log in with
+```
+vagrant ssh
+```
+Inside the VM, run the following commands to build and run the service:
+```
+cd /vagrant
+./conf.d/autobuild/linux/autobuild build
+afb-daemon --verbose --ldpaths=build/agl-speech-afb --port 1235 --token mytoken
+```
+
+In another window, you can connect to the service with
+```
+afb-client-demo -H ws://localhost:1235/api?token=mytoken
+```
+
+Type
+`agl-speech subscribe`
+to subscribe to events, and then
+`agl-speech tts_play_prompt {"language":"en-US","text":"Hello AGL! What can I do for you?"}`
+to trigger a fake TTS prompt
+
+A list of languages is available at
+`agl-speech tts_get_available_languages`
+
+Speech to text works like this (assume the user said "Please set the temperature to 70 degrees"):
+`agl-speech stt_recognize`
+
+Overall, the output looks like this:
+```
+vagrant@ubuntu-xenial:~$ afb-client-demo -H ws://localhost:1235/api?token=mytoken
+agl-speech subscribe
+ON-REPLY 1:agl-speech/subscribe: OK
+{
+ "response":{
+ "status":"ok"
+ },
+ "jtype":"afb-reply",
+ "request":{
+ "status":"success",
+ "info":"subscribed to all events",
+ "uuid":"27fa106c-4053-42d6-a1cb-b4ed3d4faba7"
+ }
+}
+agl-speech tts_play_prompt {"language":"en-US","text":"Hello AGL! What can I do for you?"}
+ON-REPLY 2:agl-speech/tts_play_prompt: OK
+{
+ "response":{
+ "status":"ok"
+ },
+ "jtype":"afb-reply",
+ "request":{
+ "status":"success",
+ "info":"tts_play_prompt"
+ }
+}
+ON-EVENT agl-speech/event_tts_prompt_playing:
+{
+ "event":"agl-speech\/event_tts_prompt_playing",
+ "data":{
+ "text":"Hello AGL! What can I do for you?",
+ "language":"en-US",
+ "elapsed_time_us":2500000
+ },
+ "jtype":"afb-event"
+}
+ON-EVENT agl-speech/event_tts_prompt_completed:
+{
+ "event":"agl-speech\/event_tts_prompt_completed",
+ "data":{
+ "text":"Hello AGL! What can I do for you?",
+ "language":"en-US",
+ "elapsed_time_ms":3000
+ },
+ "jtype":"afb-event"
+}
+agl-speech tts_get_available_languages
+ON-REPLY 3:agl-speech/tts_get_available_languages: OK
+{
+ "response":{
+ "languages":[
+ "en-US"
+ ]
+ },
+ "jtype":"afb-reply",
+ "request":{
+ "status":"success",
+ "info":"tts_get_available_languages"
+ }
+}
+agl-speech stt_recognize
+ON-REPLY 4:agl-speech/stt_recognize: OK
+{
+ "response":{
+ "status":"ok"
+ },
+ "jtype":"afb-reply",
+ "request":{
+ "status":"success",
+ "info":"stt_recognize"
+ }
+}
+ON-EVENT agl-speech/event_stt_final_result:
+{
+ "event":"agl-speech\/event_stt_final_result",
+ "data":{
+ "time_offset_usec":5000000,
+ "result":{
+ "confidence":0.990000,
+ "domain":"hvac",
+ "intent":"set_temperature",
+ "slots":[
+ {
+ "name":"temperature",
+ "value":"70"
+ }
+ ]
+ }
+ },
+ "jtype":"afb-event"
+}
+```
diff --git a/Vagrantfile b/Vagrantfile new file mode 100644 index 0000000..1642c49 --- /dev/null +++ b/Vagrantfile @@ -0,0 +1,50 @@ +# -*- mode: ruby -*-
+# vi: set ft=ruby :
+
+Vagrant.configure("2") do |config|
+ config.vm.box = "ubuntu/xenial64"
+
+ config.vm.provider "virtualbox" do |vb|
+ vb.memory = "2048"
+ end
+
+ config.vm.network "forwarded_port", guest: 1235, host: 1235
+
+ config.vm.provision "shell", inline: <<-SHELL
+
+ export DISTRO="xUbuntu_16.04"
+ export BRANCH="AGL_ElectricEel"
+ wget -O - http://download.opensuse.org/repositories/isv:/LinuxAutomotive:/${BRANCH}/${DISTRO}/Release.key | sudo apt-key add -
+ echo "deb http://download.opensuse.org/repositories/isv:/LinuxAutomotive:/${BRANCH}/${DISTRO}/ ./" >> /etc/apt/sources.list.d/AGL.list
+
+
+ apt-get update
+ apt-get install -y \
+ build-essential \
+ git \
+ curl \
+ wget \
+ cmake \
+ pkg-config \
+ libjson-c-dev \
+ libsystemd-dev \
+ agl-xds-agent \
+ agl-app-framework-binder-bin \
+ agl-app-framework-binder-dev
+
+ apt-get -y dist-upgrade
+
+ # Source the profile script in bashrc so that it is also available
+ # for non-login shells
+ echo ". /etc/profile.d/AGL_app-framework-binder.sh" >> /etc/bash.bashrc
+
+ mkdir -p $HOME/tmp
+ cd $HOME/tmp
+ wget https://ftp.gnu.org/gnu/libmicrohttpd/libmicrohttpd-0.9.55.tar.gz
+ tar xzf libmicrohttpd-0.9.55.tar.gz
+ cd libmicrohttpd-0.9.55
+ ./configure && make && sudo make install
+ cd ..
+ chmod +x /vagrant/conf.d/autobuild/linux/autobuild
+ SHELL
+end
diff --git a/agl-speech-afb/CMakeLists.txt b/agl-speech-afb/CMakeLists.txt new file mode 100644 index 0000000..565a3e7 --- /dev/null +++ b/agl-speech-afb/CMakeLists.txt @@ -0,0 +1,36 @@ +########################################################################### +# Copyright 2015, 2016, 2017 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. +########################################################################### + +# Add target to project dependency list +PROJECT_TARGET_ADD(simpleservice) + + # Define project Targets + file(GLOB sourcelist "*.c") + + # Define project Targets + ADD_LIBRARY(${TARGET_NAME} MODULE ${sourcelist}) + + # Binder exposes a unique public entry point + SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES + PREFIX "afb-" + LABELS "BINDING" + LINK_FLAGS ${BINDINGS_LINK_FLAG} + OUTPUT_NAME ${TARGET_NAME} + ) + + TARGET_LINK_LIBRARIES(${TARGET_NAME} + ${link_libraries} + ) diff --git a/agl-speech-afb/agl-speech-binding.c b/agl-speech-afb/agl-speech-binding.c new file mode 100644 index 0000000..bc9696e --- /dev/null +++ b/agl-speech-afb/agl-speech-binding.c @@ -0,0 +1,289 @@ +#define _GNU_SOURCE +#include <stdio.h> +#include <string.h> +#include <json-c/json.h> +#include <systemd/sd-event.h> +#include <sys/timerfd.h> + +#define AFB_BINDING_VERSION 2 +#include <afb/afb-binding.h> + +afb_event event_tts_prompt_playing, event_tts_prompt_completed, + event_stt_result; + +static void subscribe(struct afb_req request) +{ + afb_req_subscribe(request, event_tts_prompt_playing); + afb_req_subscribe(request, event_tts_prompt_completed); + afb_req_subscribe(request, event_stt_result); + + json_object *res = json_object_new_object(); + json_object_object_add(res, "status", json_object_new_string("ok")); + + afb_req_success(request, res, "subscribed to all events"); + + AFB_NOTICE("subscribe was called"); +} + +static void tts_get_available_languages(struct afb_req request) +{ + json_object *res = json_object_new_object(); + json_object *list = json_object_new_array(); + json_object_array_add(list, json_object_new_string("en-US")); + json_object_object_add(res, "languages", list); + + afb_req_success(request, res, "tts_get_available_languages"); + + AFB_NOTICE("tts_get_available_languages was called"); +} + +static int on_prompt_completed( + sd_event_source *s, + uint64_t usec, + void *userdata) +{ + AFB_NOTICE("TTS prompt completed"); + + json_object* event_json = (json_object*) userdata; + afb_event_push(event_tts_prompt_completed, event_json); + + return 0; +} + + +// Requests look like this: +// { +// "language": "en-US", +// "text": "Hello AGL! What can I do for you?" +// } +// +static void tts_play_prompt(struct afb_req request) +{ + json_object *tmpJ; + json_object *queryJ = afb_req_json(request); + + json_bool success = json_object_object_get_ex(queryJ, "language", &tmpJ); + if (!success) { + afb_req_fail_f(request, "ERROR", "key language not found in '%s'", json_object_get_string(queryJ)); + return; + } + + if (json_object_get_type(tmpJ) != json_type_string) { + afb_req_fail(request, "ERROR", "key language not a string"); + return; + } + + const char* language = json_object_get_string(tmpJ); + if (strncmp(language, "en-US", 4) != 0) { + afb_req_fail(request, "ERROR", "Only supported language for now is en-US"); + return; + } + + + success = json_object_object_get_ex(queryJ, "text", &tmpJ); + if (!success) { + afb_req_fail_f(request, "ERROR", "key text not found in '%s'", json_object_get_string(queryJ)); + return; + } + + if (json_object_get_type(tmpJ) != json_type_string) { + afb_req_fail(request, "ERROR", "key text not a string"); + return; + } + + const char* text = json_object_get_string(tmpJ); + AFB_NOTICE("Text to speech playing prompt: '%s'", text); + + json_object *res = json_object_new_object(); + json_object_object_add(res, "status", json_object_new_string("ok")); + + // return success + afb_req_success(request, res, "tts_play_prompt"); + + + // send event_tts_prompt_playing + json_object *event_playing_json = json_object_new_object(); + json_object_object_add(event_playing_json, "text", json_object_new_string(text)); + json_object_object_add(event_playing_json, "language", json_object_new_string(language)); + json_object_object_add(event_playing_json, "elapsed_time_us", json_object_new_int(2500000)); + + afb_event_push(event_tts_prompt_playing, event_playing_json); + + + // create timer that fire event_tts_prompt_completed + struct sd_event* event_loop = afb_daemon_get_event_loop(); + + uint64_t current_time = 0; + sd_event_now( + event_loop, + CLOCK_MONOTONIC, + ¤t_time + ); + + json_object *event_completed_json = json_object_new_object(); + json_object_object_add(event_completed_json, "text", json_object_new_string(text)); + json_object_object_add(event_completed_json, "language", json_object_new_string(language)); + json_object_object_add(event_completed_json, "elapsed_time_ms", json_object_new_int(3000)); + + sd_event_add_time( + event_loop, + NULL, /* event source */ + CLOCK_MONOTONIC, + current_time + 3000000 , /* usec */ + 0, /* accuracy */ + on_prompt_completed, + event_completed_json /* userdata */ + ); +} + + +struct stt_fake_slot +{ + const char* name; + const char* value; +}; + +struct stt_fake_result +{ + int type; /* 0=intermediate, 1=final */ + int usec_delay; + double confidence; + const char* domain; + const char* intent; + const struct stt_fake_slot slots; // only one because I'm lazy +}; + +static const struct stt_fake_result stt_fake_results[] = { + { + .type = 1, + .usec_delay = 5000000, + .confidence = 0.99, + .domain = "hvac", + .intent = "set_temperature", + .slots = { + .name = "temperature", + .value = "70" + } + } +}; + +static int on_recognition_result( + sd_event_source *s, + uint64_t usec, + void *userdata) +{ + struct stt_fake_result result = stt_fake_results[0]; + AFB_NOTICE("Speech to text recognition result at offset %llu with intent '%s'", + (unsigned long long)result.usec_delay, + result.intent); + + json_object *event_json = json_object_new_object(); + + json_object *intent_result = json_object_new_object(); + json_object_object_add(intent_result, "confidence", json_object_new_double(result.confidence)); + json_object_object_add(intent_result, "domain", json_object_new_string(result.domain)); + json_object_object_add(intent_result, "intent", json_object_new_string(result.intent)); + + json_object_object_add(event_json, "time_offset_usec", json_object_new_int(result.usec_delay)); + json_object_object_add(event_json, "result", intent_result); + + json_object *slots = json_object_new_array(); + json_object *slot = json_object_new_object(); + json_object_object_add(slot, "name", json_object_new_string(result.slots.name)); + json_object_object_add(slot, "value", json_object_new_string(result.slots.value)); + json_object_array_add(slots, slot); + + json_object_object_add(intent_result, "slots", slots); + + afb_event_push(event_stt_result, event_json); + + return 0; +} + +// Configuration comes later... +static void stt_recognize(struct afb_req request) +{ + json_object *res = json_object_new_object(); + json_object_object_add(res, "status", json_object_new_string("ok")); + + afb_req_success(request, res, "stt_recognize"); + + struct sd_event* event_loop = afb_daemon_get_event_loop(); + + uint64_t current_time = 0; + sd_event_now( + event_loop, + CLOCK_MONOTONIC, + ¤t_time + ); + + sd_event_add_time( + event_loop, + NULL /* event source */, + CLOCK_MONOTONIC, + current_time + stt_fake_results[0].usec_delay , /* usec */ + 0, /* accuracy */ + on_recognition_result, + NULL /* userdata */ + ); + + AFB_NOTICE("stt_recognize was called"); +} + + +static const struct afb_auth _afb_auths_v2_monitor[] = { + {.type = afb_auth_Permission, .text = "urn:AGL:permission:monitor:public:set"}, + {.type = afb_auth_Permission, .text = "urn:AGL:permission:monitor:public:get"}, + {.type = afb_auth_Or, .first = &_afb_auths_v2_monitor[1], .next = &_afb_auths_v2_monitor[0]} +}; + +static const struct afb_verb_v2 verbs[] = { + + {.verb = "subscribe", .session = AFB_SESSION_NONE, .callback = subscribe, .auth = NULL}, + + {.verb = "tts_play_prompt", .session = AFB_SESSION_NONE, .callback = tts_play_prompt, .auth = NULL}, + {.verb = "tts_get_available_languages", .session = AFB_SESSION_NONE, .callback = tts_get_available_languages, .auth = NULL}, + + {.verb = "stt_recognize", .session = AFB_SESSION_NONE, .callback = stt_recognize, .auth = NULL}, + + {NULL} +}; + +static int init() +{ + AFB_NOTICE("init was called"); + event_tts_prompt_playing = afb_daemon_make_event("event_tts_prompt_playing"); + event_tts_prompt_completed = afb_daemon_make_event("event_tts_prompt_completed"); + event_stt_result = afb_daemon_make_event("event_stt_final_result"); + + if (!afb_event_is_valid(event_tts_prompt_playing) || + !afb_event_is_valid(event_tts_prompt_completed) || + !afb_event_is_valid(event_stt_result)) + { + AFB_ERROR("Failed to create events!"); + return -1; + } + + return 0; +} + +static int preinit() +{ + AFB_NOTICE("preinit was called"); + return 0; +} + +static void onevent(const char *event, struct json_object *object) +{ + AFB_NOTICE("onevent called with event %s", event); +} + +const struct afb_binding_v2 afbBindingV2 = { + .api = "agl-speech", + .specification = NULL, + .verbs = verbs, + .preinit = preinit, + .init = init, + .onevent = onevent, + .noconcurrency = 0 +}; diff --git a/conf.d/app-templates b/conf.d/app-templates new file mode 160000 +Subproject a3c312ece0a77310a9d8ecde1dd0f1267646f4f diff --git a/conf.d/autobuild/agl/autobuild b/conf.d/autobuild/agl/autobuild new file mode 100755 index 0000000..83097ab --- /dev/null +++ b/conf.d/autobuild/agl/autobuild @@ -0,0 +1,67 @@ +#!/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. + +THISFILE := $(lastword $(MAKEFILE_LIST)) +BUILD_DIR := $(abspath $(dir $(THISFILE)/../../../../..)/build) +DEST := ${BUILD_DIR}/target + +.PHONY: all clean distclean configure build package help update + +all: help + +help: + @echo "List of targets available:" + @echo "" + @echo "- all" + @echo "- clean" + @echo "- distclean" + @echo "- configure" + @echo "- build: compilation, link and prepare files for package into a widget" + @echo "- package: output a widget file '*.wgt'" + @echo "- install: install in your ${CMAKE_INSTALL_DIR} directory" + @echo "" + @echo "Usage: ./conf.d/autobuild/agl/autobuild package DEST=${HOME}/opt" + @echo "Don't use your build dir as DEST as wgt file is generated at this location" + +update: configure + @cmake --build ${BUILD_DIR} --target autobuild + +clean: + @([ -d ${BUILD_DIR} ] && make -C ${BUILD_DIR} clean) || echo Nothing to clean + +distclean: + @rm -rf ${BUILD_DIR} + +configure: ${BUILD_DIR}/Makefile + +build: configure + @cmake --build ${BUILD_DIR} ${BUILD_ARGS} --target all + +package: build + @mkdir -p ${BUILD_DIR}/$@/bin + @mkdir -p ${BUILD_DIR}/$@/etc + @mkdir -p ${BUILD_DIR}/$@/lib + @mkdir -p ${BUILD_DIR}/$@/htdocs + @mkdir -p ${BUILD_DIR}/$@/var + @cmake --build ${BUILD_DIR} --target widget + @mkdir -p ${DEST} && cp ${BUILD_DIR}/*wgt ${DEST} + +install: build + @cmake --build ${BUILD_DIR} --target install + +${BUILD_DIR}/Makefile: + @[ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR} + @[ -f ${BUILD_DIR}/Makefile ] || (cd ${BUILD_DIR} && cmake ${CONFIGURE_ARGS} ..) diff --git a/conf.d/autobuild/linux/autobuild b/conf.d/autobuild/linux/autobuild new file mode 100755 index 0000000..83097ab --- /dev/null +++ b/conf.d/autobuild/linux/autobuild @@ -0,0 +1,67 @@ +#!/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. + +THISFILE := $(lastword $(MAKEFILE_LIST)) +BUILD_DIR := $(abspath $(dir $(THISFILE)/../../../../..)/build) +DEST := ${BUILD_DIR}/target + +.PHONY: all clean distclean configure build package help update + +all: help + +help: + @echo "List of targets available:" + @echo "" + @echo "- all" + @echo "- clean" + @echo "- distclean" + @echo "- configure" + @echo "- build: compilation, link and prepare files for package into a widget" + @echo "- package: output a widget file '*.wgt'" + @echo "- install: install in your ${CMAKE_INSTALL_DIR} directory" + @echo "" + @echo "Usage: ./conf.d/autobuild/agl/autobuild package DEST=${HOME}/opt" + @echo "Don't use your build dir as DEST as wgt file is generated at this location" + +update: configure + @cmake --build ${BUILD_DIR} --target autobuild + +clean: + @([ -d ${BUILD_DIR} ] && make -C ${BUILD_DIR} clean) || echo Nothing to clean + +distclean: + @rm -rf ${BUILD_DIR} + +configure: ${BUILD_DIR}/Makefile + +build: configure + @cmake --build ${BUILD_DIR} ${BUILD_ARGS} --target all + +package: build + @mkdir -p ${BUILD_DIR}/$@/bin + @mkdir -p ${BUILD_DIR}/$@/etc + @mkdir -p ${BUILD_DIR}/$@/lib + @mkdir -p ${BUILD_DIR}/$@/htdocs + @mkdir -p ${BUILD_DIR}/$@/var + @cmake --build ${BUILD_DIR} --target widget + @mkdir -p ${DEST} && cp ${BUILD_DIR}/*wgt ${DEST} + +install: build + @cmake --build ${BUILD_DIR} --target install + +${BUILD_DIR}/Makefile: + @[ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR} + @[ -f ${BUILD_DIR}/Makefile ] || (cd ${BUILD_DIR} && cmake ${CONFIGURE_ARGS} ..) diff --git a/conf.d/cmake/config.cmake b/conf.d/cmake/config.cmake new file mode 100644 index 0000000..3f1c8f7 --- /dev/null +++ b/conf.d/cmake/config.cmake @@ -0,0 +1,184 @@ +########################################################################### +# 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(PROJECT_NAME helloworld-service) +set(PROJECT_VERSION "1.0") +set(PROJECT_PRETTY_NAME "Helloworld for AGL") +set(PROJECT_DESCRIPTION "Provide an AGL Helloworld Binding") +set(PROJECT_URL "https://github.com/iotbzh/helloworld-service") +set(PROJECT_ICON "icon.png") +set(PROJECT_AUTHOR "Iot-Team") +set(PROJECT_AUTHOR_MAIL "secretaria@iot.bzh") +set(PROJECT_LICENSE "APL2.0") +set(PROJECT_LANGUAGES,"C") + +# Where are stored default templates files from submodule or subtree app-templates in your project tree +# relative to the root project directory +set(PROJECT_APP_TEMPLATES_DIR "conf.d/app-templates") + +# Where are stored your external libraries for your project. This is 3rd party library that you don't maintain +# but used and must be built and linked. +# set(PROJECT_LIBDIR "libs") + +# Where are stored data for your application. Pictures, static resources must be placed in that folder. +# set(PROJECT_RESOURCES "data") + +# Which directories inspect to find CMakeLists.txt target files +# set(PROJECT_SRC_DIR_PATTERN "*") + +# Compilation Mode (DEBUG, RELEASE) +# ---------------------------------- +set(CMAKE_BUILD_TYPE "DEBUG") + +# Kernel selection if needed. You can choose between a +# mandatory version to impose a minimal version. +# Or check Kernel minimal version and just print a Warning +# about missing features and define a preprocessor variable +# to be used as preprocessor condition in code to disable +# incompatibles features. Preprocessor define is named +# KERNEL_MINIMAL_VERSION_OK. +# +# NOTE*** FOR NOW IT CHECKS KERNEL Yocto environment and +# Yocto SDK Kernel version. +# ----------------------------------------------- +#set (kernel_mandatory_version 4.8) +#set (kernel_minimal_version 4.8) + +# Compiler selection if needed. Impose a minimal version. +# ----------------------------------------------- +set (gcc_minimal_version 4.9) + +# PKG_CONFIG required packages +# ----------------------------- +set (PKG_REQUIRED_LIST + json-c + libsystemd>=222 + afb-daemon + libmicrohttpd>=0.9.55 +) + + +# Print a helper message when every thing is finished +# ---------------------------------------------------- +if(IS_DIRECTORY $ENV{HOME}/opt/afb-monitoring) +set(MONITORING_ALIAS "--alias=/monitoring:$ENV{HOME}/opt/afb-monitoring") +endif() +set(CLOSING_MESSAGE "Debug from afb-daemon --port=1234 ${MONITORING_ALIAS} --ldpaths=package --workdir=. --roothttp=../htdocs --token= --verbose ") +set(PACKAGE_MESSAGE "Install widget file using in the target : afm-util install ${PROJECT_NAME}.wgt") + +# Customize link option +# ----------------------------- +#list(APPEND link_libraries -an-option) + +# Compilation options definition +# Use CMake generator expressions to specify only for a specific language +# Values are prefilled with default options that is currently used. +# Either separate options with ";", or each options must be quoted separately +# DO NOT PUT ALL OPTION QUOTED AT ONCE , COMPILATION COULD FAILED ! +# ---------------------------------------------------------------------------- +#set(COMPILE_OPTIONS "-Wall" "-Wextra" "-Wconversion" "-Wno-unused-parameter" "-Wno-sign-compare" "-Wno-sign-conversion" "-Werror=maybe-uninitialized" "-Werror=implicit-function-declaration" "-ffunction-sections" "-fdata-sections" "-fPIC" CACHE STRING "Compilation flags") +#set(C_COMPILE_OPTIONS "" CACHE STRING "Compilation flags for C language.") +#set(CXX_COMPILE_OPTIONS "" CACHE STRING "Compilation flags for C++ language.") +#set(PROFILING_COMPILE_OPTIONS "-g" "-O0" "-pg" "-Wp,-U_FORTIFY_SOURCE" CACHE STRING "Compilation flags for PROFILING build type.") +#set(DEBUG_COMPILE_OPTIONS "-g" "-ggdb" "-Wp,-U_FORTIFY_SOURCE" CACHE STRING "Compilation flags for DEBUG build type.") +#set(CCOV_COMPILE_OPTIONS "-g" "-O2" "--coverage" CACHE STRING "Compilation flags for CCOV build type.") +#set(RELEASE_COMPILE_OPTIONS "-g" "-O2" CACHE STRING "Compilation flags for RELEASE build type.") + +# Print a helper message when every thing is finished +# ---------------------------------------------------- +#set(CLOSING_MESSAGE "") +#set(PACKAGE_MESSAGE "Install widget file using in the target : afm-util install ${PROJECT_NAME}.wgt") + +# (BUG!!!) as PKG_CONFIG_PATH does not work [should be an env variable] +# --------------------------------------------------------------------- +set(CMAKE_INSTALL_PREFIX $ENV{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 location for config.xml.in +# ----------------------------------- +set(WIDGET_ICON ${PROJECT_APP_TEMPLATES_DIR}/wgt/${PROJECT_ICON}) +set(WIDGET_CONFIG_TEMPLATE ${CMAKE_SOURCE_DIR}/conf.d/wgt/config.xml.in CACHE PATH "Path to widget config file template (config.xml.in)") + +# Mandatory widget Mimetype specification of the main unit +# -------------------------------------------------------------------------- +# Choose between : +#- text/html : HTML application, +# content.src designates the home page of the application +# +#- application/vnd.agl.native : AGL compatible native, +# content.src designates the relative path of the binary. +# +# - application/vnd.agl.service: AGL service, content.src is not used. +# +#- ***application/x-executable***: Native application, +# content.src designates the relative path of the binary. +# For such application, only security setup is made. +# +set(WIDGET_TYPE application/vnd.agl.service) + +# Mandatory Widget entry point file of the main unit +# -------------------------------------------------------------- +# This is the file that will be executed, loaded, +# at launch time by the application framework. +# +set(WIDGET_ENTRY_POINT config.xml) + +# 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 PrefixPath ) + +# Optional force binding Linking flag +# ------------------------------------ +# set(BINDINGS_LINK_FLAG LinkOptions ) + +# Optional force package prefix generation, like widget +# ----------------------------------------------------- +# set(PKG_PREFIX DestinationPath) + +# Optional Application Framework security token +# and port use for remote debugging. +#------------------------------------------------------------ +#set(AFB_TOKEN "" CACHE PATH "Default AFB_TOKEN") +#set(AFB_REMPORT "1234" CACHE PATH "Default AFB_TOKEN") + +# Optional schema validator about now only XML, LUA and JSON +# are supported +#------------------------------------------------------------ +#set(LUA_CHECKER "luac" CACHE STRING "LUA compiler") +#set(XML_CHECKER "xmllint" CACHE STRING "XML linter") +#set(JSON_CHECKER "json_verify" CACHE STRING "JSON linter") + +# This include is mandatory and MUST happens at the end +# of this file, else you expose you to unexpected behavior +# ----------------------------------------------------------- +include(${PROJECT_APP_TEMPLATES_DIR}/cmake/common.cmake) diff --git a/conf.d/packaging/agl-helloworld-service.dsc b/conf.d/packaging/agl-helloworld-service.dsc new file mode 100644 index 0000000..d883851 --- /dev/null +++ b/conf.d/packaging/agl-helloworld-service.dsc @@ -0,0 +1,18 @@ +Format: 1.0 +Source: agl-helloworld-service +Binary: agl-helloworld-service-bin +Architecture: any +Version: 2.0-0 +Maintainer: Iot-Team <secretaria@iot.bzh> +Standards-Version: 3.8.2 +Homepage: https://github.com/iotbzh/helloworld-service +Build-Depends: debhelper (>= 5), + pkg-config, + cmake, + gcc, + g++, + libjson-c-dev , + libsystemd-dev (>= 222), + agl-app-framework-binder-dev , + agl-libmicrohttpd-dev (>= 0.9.55) +Debtransform-Tar: agl-helloworld-service_1.0.orig.tar.gz diff --git a/conf.d/packaging/agl-helloworld-service.spec b/conf.d/packaging/agl-helloworld-service.spec new file mode 100644 index 0000000..d495571 --- /dev/null +++ b/conf.d/packaging/agl-helloworld-service.spec @@ -0,0 +1,66 @@ +########################################################################### +# Copyright 2015, 2016, 2017 IoT.bzh +# +# author: Iot-Team <secretaria@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. +########################################################################### + + +Name: agl-helloworld-service +Version: 1.0 +Release: 1 +Group: AGL +License: APL2.0 +Summary: Provide an AGL Helloworld Binding +Url: https://github.com/iotbzh/helloworld-service +Source0: %{name}_%{version}.orig.tar.gz + +BuildRequires: cmake +BuildRequires: gcc gcc-c++ +BuildRequires: pkgconfig(json-c) +BuildRequires: pkgconfig(libsystemd) >= 222 +BuildRequires: pkgconfig(afb-daemon) +BuildRequires: pkgconfig(libmicrohttpd) >= 0.9.55 + + +BuildRoot: %{_tmppath}/%{name}-%{version}-build + +%define _prefix /opt/AGL/helloworld-service +%define __cmake cmake + +%description +Provide an AGL Helloworld Binding + +%prep +%setup -q + +%build +%cmake -DCMAKE_INSTALL_PREFIX:PATH=%{_libdir} +make %{?_smp_mflags} + +%install +CURDIR=$(pwd) +[ -d build ] && cd build +make populate +mkdir -p %{?buildroot}%{_prefix} +cp -r package/* %{?buildroot}%{_prefix} + +cd $CURDIR +find %{?buildroot}%{_prefix} -type d -exec echo "%dir {}" \;>> pkg_file +find %{?buildroot}%{_prefix} -type f -exec echo "{}" \;>> pkg_file +sed -i 's@%{?buildroot}@@g' pkg_file + + +%files -f pkg_file +%defattr(-,root,root) diff --git a/conf.d/packaging/debian.agl-helloworld-service.install b/conf.d/packaging/debian.agl-helloworld-service.install new file mode 100644 index 0000000..5858efd --- /dev/null +++ b/conf.d/packaging/debian.agl-helloworld-service.install @@ -0,0 +1,2 @@ +/opt/AGL/* +/etc/profile.d/* diff --git a/conf.d/packaging/debian.changelog b/conf.d/packaging/debian.changelog new file mode 100644 index 0000000..d668686 --- /dev/null +++ b/conf.d/packaging/debian.changelog @@ -0,0 +1,5 @@ +agl-helloworld-service (1.0-0) UNRELEASED; urgency=low + + * init build + + -- Iot-Team <secretaria@iot.bzh> Mon, 25 Dec 2007 10:50:38 +0100 diff --git a/conf.d/packaging/debian.compat b/conf.d/packaging/debian.compat new file mode 100644 index 0000000..45a4fb7 --- /dev/null +++ b/conf.d/packaging/debian.compat @@ -0,0 +1 @@ +8 diff --git a/conf.d/packaging/debian.control b/conf.d/packaging/debian.control new file mode 100644 index 0000000..31461d6 --- /dev/null +++ b/conf.d/packaging/debian.control @@ -0,0 +1,19 @@ +Priority: optional +Maintainer: Iot-Team <secretaria@iot.bzh> +Source: agl-helloworld-service +Build-Depends: debhelper (>= 5), + pkg-config, + cmake, + gcc, + g++, + libjson-c-dev , + libsystemd-dev (>= 222), + agl-app-framework-binder-dev , + agl-libmicrohttpd-dev (>= 0.9.55) +Standards-Version: 3.8.2 +Homepage: https://github.com/iotbzh/helloworld-service + +Package: agl-helloworld-service +Section: libs +Architecture: any +Description: Provide an AGL Helloworld Binding diff --git a/conf.d/packaging/debian.rules b/conf.d/packaging/debian.rules new file mode 100644 index 0000000..fd8a335 --- /dev/null +++ b/conf.d/packaging/debian.rules @@ -0,0 +1,87 @@ +#!/usr/bin/make -f +# -*- makefile -*- +# Uncomment this to turn on verbose mode. +export DH_VERBOSE=1 + +# These are used for cross-compiling and for saving the configure script +# from having to guess our platform (since we know it already) +DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) +DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) + + +CFLAGS = -Wall -g + +ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) + CFLAGS += -O0 +else + CFLAGS += -O2 +endif +ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) + INSTALL_PROGRAM += -s +endif + +configure: configure-stamp +configure-stamp: + dh_testdir + # + touch configure-stamp + +build: build-stamp +build-stamp: configure-stamp + dh_testdir + mkdir -p build + cd build;cmake ../ -DCMAKE_INSTALL_PREFIX:PATH=/opt/AGL/helloworld-service -DCMAKE_INSTALL_LIBDIR:PATH=lib/$(DEB_HOST_MULTIARCH);$(MAKE) + # + touch build-stamp + +clean: + #dh_testdir + dh_testroot + rm -f configure-stamp build-stamp + [ ! -f Makefile ] || $(MAKE) distclean + #dh_clean + +install: build + dh_testdir + dh_testroot + dh_prep + dh_installdirs + # Add here commands to install the package into debian/tmp + mkdir -p debian/tmp/opt/AGL/helloworld-service;cd build;make populate;cp -r package/* ../debian/tmp/opt/AGL/helloworld-service/ + mkdir -p debian/tmp/etc/profile.d + echo '#---------- AGL helloworld-service options Start ---------" ' > debian/tmp/etc/profile.d/AGL_helloworld-service.sh + echo '# Object: AGL cmake option for binder/bindings' >> debian/tmp/etc/profile.d/AGL_helloworld-service.sh + echo 'export LD_LIBRARY_PATH=/opt/AGL/helloworld-service/lib/$(DEB_HOST_MULTIARCH):$$LD_LIBRARY_PATH' >> debian/tmp/etc/profile.d/AGL_helloworld-service.sh + echo 'export LIBRARY_PATH=/opt/AGL/helloworld-service/lib/$(DEB_HOST_MULTIARCH):$$LIBRARY_PATH' >> debian/tmp/etc/profile.d/AGL_helloworld-service.sh + echo 'export PATH=/opt/AGL/helloworld-service/bin:$$PATH' >> debian/tmp/etc/profile.d/AGL_helloworld-service.sh + echo '#---------- AGL options End ---------' >> debian/tmp/etc/profile.d/AGL_helloworld-service.sh + # Move all files in their corresponding package + dh_install --list-missing -s --sourcedir=debian/tmp + # empty dependency_libs in .la files + #sed -i "/dependency_libs/ s/'.*'/''/" `find debian/ -name '*.la'` + +# Build architecture-independent files here. +binary-indep: build install +# We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir + dh_testroot + dh_installchangelogs + dh_installdocs + dh_installexamples + dh_installman + dh_link + dh_strip + dh_compress + dh_fixperms + dh_makeshlibs -V + dh_installdeb + dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install diff --git a/conf.d/wgt/config.xml.in b/conf.d/wgt/config.xml.in new file mode 100644 index 0000000..19f6f33 --- /dev/null +++ b/conf.d/wgt/config.xml.in @@ -0,0 +1,15 @@ +<?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="@PROJECT_ICON@"/> + <content src="@WIDGET_ENTRY_POINT@" type="@WIDGET_TYPE@"/> + <description>@PROJECT_DESCRIPTION@</description> + <author>@PROJECT_AUTHOR@ <@PROJECT_AUTHOR_MAIL@></author> + <license>@PROJECT_LICENSE@</license> + <feature name="urn:AGL:widget:provided-api"> + <param name="helloworld" value="ws" /> + </feature> + <feature name="urn:AGL:widget:required-api"> + <param name="lib/afb-helloworld.so" value="local" /> + </feature> +</widget> |