iotjs update 2018.05.03 accepted/tizen/4.0/unified/20180508.071454 accepted/tizen/unified/20180508.071441 submit/tizen/20180503.130743 submit/tizen_4.0/20180503.130810
authorHaesik Jun <haesik.jun@samsung.com>
Thu, 3 May 2018 12:54:46 +0000 (21:54 +0900)
committerHaesik Jun <haesik.jun@samsung.com>
Thu, 3 May 2018 12:54:46 +0000 (21:54 +0900)
github commitid: 94115221b0cdfa40060b660fd34cbe3a3607e634

Change-Id: I60f89c60ad68e9939d6c49baef0d499ba171ef59
Signed-off-by: Haesik Jun <haesik.jun@samsung.com>
41 files changed:
.travis.yml
CMakeLists.txt
README.md
cmake/iotjs.cmake
config/tizen/packaging/iotjs.spec
config/tizen/patch4tizenorg.sh [new file with mode: 0755]
config/tizen/template/IoTjsApp/project/src/main.c
docs/api/IoT.js-API-GPIO.md
docs/api/IoT.js-API-I2C.md
docs/api/IoT.js-API-MQTT.md [new file with mode: 0644]
docs/api/IoT.js-API-Module.md
docs/api/IoT.js-API-Process.md
docs/api/IoT.js-API-SPI.md
docs/api/IoT.js-API-UART.md
docs/targets/tizen/SystemIO-Pin-Information-Tizen.md [new file with mode: 0644]
packaging/iotjs.spec
samples/bridge_sample/src/iotjs_bridge_sample.c
samples/tizen-bridge-native/tizen_bridge_native.c [new file with mode: 0644]
samples/tizen-bridge-native/tizen_bridge_native.js [moved from test/run_pass/issue/issue-1351.js with 61% similarity]
sonar-project.properties [new file with mode: 0644]
src/iotjs_magic_strings.h
src/iotjs_util.c
src/iotjs_util.h
src/js/iotjs.js
src/js/module.js
src/js/mqtt.js [new file with mode: 0644]
src/js/tizen.js
src/modules.json
src/modules/iotjs_module_bridge.c
src/modules/iotjs_module_i2c.c
src/modules/iotjs_module_mqtt.c [new file with mode: 0644]
src/modules/iotjs_module_mqtt.h [new file with mode: 0644]
src/modules/iotjs_module_process.c
src/modules/tizen/iotjs_module_tizen-tizen.c
src/platform/tizen/iotjs_tizen_service_app.c
src/platform/tizen/iotjs_tizen_service_app.h
test/run_pass/test_process_readsource.js [deleted file]
test/testsets.json
test/tools/systemio_common.js
tools/build.py
tools/check_sonarqube.sh [new file with mode: 0755]

index 8353bff..2916ac0 100644 (file)
@@ -70,4 +70,15 @@ matrix:
           build_command: "tools/travis_script.py"
           branch_pattern: master
       env: OPTS="coverity"
+    - os: linux
+      addons:
+        sonarcloud:
+          organization: "samsung-iotjs"
+          token:
+            secure: "u9HWNQNhAqQQdgl3yldKcQVH8plMQRwIdpzjsM4j3GBC4Wrh9u8guLJB3o003i0UsyaGg2knYFdLgOmEsgcvXAo2aIUyzf9CfK9RLRw5RtIuPMpmR7UjHdlf+QfCF+nY+BB2j0nAiWnxHve95du7sZflNxi+eNJJzquyBh1Wm8eqwoiRpCgiDzjRDEAUoz0FWMNny/x5545E970jpQ2bjHGx98tCMUO8ikINeL8sC99sumffaFONG8GVpwLjc8McfQfYpWbk0e0OPxZtGDyqKcyMxcbAGctklsigtsBZKlpj69uba3w4OSA3zJPCdQ4dKwCyBOcAAP8qeF5Jf0eLI8WLEgnKir2Pfc/rKkY0owuz7S+tUmizm3+T06wDFgwpLu0/PcA5oOcp4WpGXbAX7WujaAHB7YKAEsk324XC7Bdf+39OuZ0dbKWMiwU7rYV4NOYNPjN2BCb1XqyE0Ung41Ls6P4t/zwzYRZtiovhr6ibNBcwLVclfQZ/tbyBDuh++8dh7Ixe+x5RFiiCB0w/fiKqqXYM8/we4JU3f71y4DK6fP+nSN/vIYttvkN28HCCvBVSdyuuvPRM6Ro1yLNw9U9PHCJ1CIgcx8+I8Mep3PzBhDILXWjzlVu4sa/+aIoEq7MvWBDMhrFEP6RX+M6CiPmgj5+Lu/GZNivbu51RASI="
+      script: ./tools/check_sonarqube.sh
+      cache:
+        directories:
+          - '$HOME/.sonar/cache'
+      env: OPTS="sonarqube"
   fast_finish: true
index acf9c19..bc9c4cf 100644 (file)
@@ -13,6 +13,7 @@
 # limitations under the License.
 
 cmake_minimum_required(VERSION 2.8)
+include(CheckCCompilerFlag)
 
 project(IOTJS C)
 
@@ -67,9 +68,18 @@ macro(iotjs_add_link_flags)
   iotjs_add_flags(IOTJS_LINKER_FLAGS ${ARGV})
 endmacro()
 
+CHECK_C_COMPILER_FLAG(-no-pie HAS_NO_PIE)
+
 # Add buildtype-related flags
 if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
   iotjs_add_compile_flags(-DDEBUG -DENABLE_DEBUG_LOG)
+  if(HAS_NO_PIE)
+    iotjs_add_link_flags(-no-pie)
+  endif()
+endif()
+
+if (CREATE_SHARED_LIB)
+  iotjs_add_compile_flags(-fPIC)
 endif()
 
 if(EXPERIMENTAL)
index 7b4f7bd..fcde96f 100644 (file)
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ The following table shows the latest results on the devices:
 
 |      Artik053         | [![Remote Testrunner](https://firebasestorage.googleapis.com/v0/b/remote-testrunner.appspot.com/o/status%2Fiotjs%2Fartik053.svg?alt=media&token=1)](https://samsung.github.io/iotjs-test-results/?view=artik053)  |
 |        :---:          |                                             :---:                                                                                                |
+| **Artik530**    | [![Remote Testrunner](https://firebasestorage.googleapis.com/v0/b/remote-testrunner.appspot.com/o/status%2Fiotjs%2Fartik530.svg?alt=media&token=1)](https://samsung.github.io/iotjs-test-results/?view=artik530)          |
 | **Raspberry Pi 2**    | [![Remote Testrunner](https://firebasestorage.googleapis.com/v0/b/remote-testrunner.appspot.com/o/status%2Fiotjs%2Frpi2.svg?alt=media&token=1)](https://samsung.github.io/iotjs-test-results/?view=rpi2)          |
 | **STM32F4-Discovery** | [![Remote Testrunner](https://firebasestorage.googleapis.com/v0/b/remote-testrunner.appspot.com/o/status%2Fiotjs%2Fstm32f4dis.svg?alt=media&token=1)](https://samsung.github.io/iotjs-test-results/?view=stm32f4dis)   |
 
index 0dcaf0b..4a7b5b3 100644 (file)
@@ -463,14 +463,14 @@ message(STATUS "TARGET_SYSTEMROOT        ${TARGET_SYSTEMROOT}")
 iotjs_add_compile_flags(${IOTJS_MODULE_DEFINES})
 
 # Configure the libiotjs.a
-set(TARGET_LIB_IOTJS libiotjs)
-add_library(${TARGET_LIB_IOTJS} STATIC ${LIB_IOTJS_SRC})
-set_target_properties(${TARGET_LIB_IOTJS} PROPERTIES
+set(TARGET_STATIC_IOTJS libiotjs)
+add_library(${TARGET_STATIC_IOTJS} STATIC ${LIB_IOTJS_SRC})
+set_target_properties(${TARGET_STATIC_IOTJS} PROPERTIES
   OUTPUT_NAME iotjs
   ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
 )
-target_include_directories(${TARGET_LIB_IOTJS} PRIVATE ${IOTJS_INCLUDE_DIRS})
-target_link_libraries(${TARGET_LIB_IOTJS}
+target_include_directories(${TARGET_STATIC_IOTJS} PRIVATE ${IOTJS_INCLUDE_DIRS})
+target_link_libraries(${TARGET_STATIC_IOTJS}
   ${JERRY_LIBS}
   ${TUV_LIBS}
   libhttp-parser
@@ -486,7 +486,27 @@ if("${BIN_INSTALL_DIR}" STREQUAL "")
   set(BIN_INSTALL_DIR "bin")
 endif()
 
-install(TARGETS ${TARGET_LIB_IOTJS} DESTINATION ${LIB_INSTALL_DIR})
+install(TARGETS ${TARGET_STATIC_IOTJS} DESTINATION ${LIB_INSTALL_DIR})
+
+# Configure the libiotjs.so
+if (NOT BUILD_LIB_ONLY AND CREATE_SHARED_LIB)
+  set(TARGET_SHARED_IOTJS shared_iotjs)
+  add_library(${TARGET_SHARED_IOTJS} SHARED)
+  set_target_properties(${TARGET_SHARED_IOTJS} PROPERTIES
+    LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
+    LIBRARY_OUTPUT_NAME iotjs
+    LINKER_LANGUAGE C
+  )
+  target_link_libraries(${TARGET_SHARED_IOTJS}
+    -Wl,--whole-archive
+    ${TARGET_STATIC_IOTJS}
+    ${JERRY_LIBS}
+    ${TUV_LIBS}
+    libhttp-parser
+    ${MBEDTLS_LIBS}
+    -Wl,--no-whole-archive
+    ${EXTERNAL_LIBS})
+endif()
 
 # Configure the iotjs executable
 if(NOT BUILD_LIB_ONLY)
@@ -497,7 +517,7 @@ if(NOT BUILD_LIB_ONLY)
     RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
   )
   target_include_directories(${TARGET_IOTJS} PRIVATE ${IOTJS_INCLUDE_DIRS})
-  target_link_libraries(${TARGET_IOTJS} ${TARGET_LIB_IOTJS})
+  target_link_libraries(${TARGET_IOTJS} ${TARGET_STATIC_IOTJS})
   install(TARGETS ${TARGET_IOTJS} DESTINATION ${BIN_INSTALL_DIR})
 
   add_subdirectory(test)
index 9a4f66c..37a7ccd 100644 (file)
@@ -64,7 +64,7 @@ cat LICENSE
 cp %{SOURCE1001} .
 
 %build
-./tools/build.py \
+V=1 VERBOSE=1 ./tools/build.py \
   --clean \
   --buildtype=%{build_mode} \
   --profile=test/profiles/tizen.profile \
@@ -76,26 +76,23 @@ cp %{SOURCE1001} .
   --external-lib=dlog \
   --external-lib=bundle \
   --external-lib=capi-appfw-app-control \
+  --external-lib=appcore-agent \
+  --external-lib=pthread \
+  --external-lib=curl \
   --external-include-dir=/usr/include/dlog/ \
   --external-include-dir=/usr/include/appcore-agent/ \
   --external-include-dir=/usr/include/appfw/ \
   --external-include-dir=/usr/include/glib-2.0/ \
   --external-include-dir=/usr/lib/glib-2.0/include/ \
   --compile-flag=-D__TIZEN__ \
-  --compile-flag=-fPIC \
+  --compile-flag=-DENABLE_DEBUG_LOG \
   --jerry-cmake-param=-DENABLE_STATIC_LINK=OFF \
+  --create-shared-lib \
   --no-init-submodule \
   --no-parallel-build \
   %{external_build_options}
 # --external-lib=sdkapi \
 
-# Create shared library
-%define iotjs_target_lib libjerry-core.a libjerry-port-default.a libhttpparser.a libtuv.a \\\
-  libmbedx509.a libmbedtls.a libmbedcrypto.a libiotjs.a
-%define iotjs_lib_flag -lcapi-system-peripheral-io -lpthread -lcurl -ldlog -lappcore-agent -lcapi-appfw-app-common -lbundle -lcapi-appfw-app-control
-cd ./build/noarch-tizen/%{build_mode}/lib/
-gcc -shared -o libiotjs.so -Wl,--whole-archive %{iotjs_target_lib} -Wl,--no-whole-archive %{iotjs_lib_flag}
-
 %install
 mkdir -p %{buildroot}%{_bindir}
 mkdir -p %{buildroot}%{_includedir}/iotjs
diff --git a/config/tizen/patch4tizenorg.sh b/config/tizen/patch4tizenorg.sh
new file mode 100755 (executable)
index 0000000..871c87d
--- /dev/null
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+# Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors
+#
+# 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.
+
+echo "******************************************************************"
+echo "*                       Tizen patch for obs build                *"
+echo "******************************************************************"
+echo ""
+echo "This working folder will be copied to ../iotjs_tizen_org"
+
+cd ..
+echo copy from $OLDPWD to ../iotjs_tizen_org
+cp -ra $OLDPWD iotjs_tizen_org
+cd iotjs_tizen_org
+
+echo -e "\n(1) Now, cloning submodules. "
+git submodule init
+
+echo -e "\n(2) Update submodules... "
+git submodule update
+
+echo -e "\n(3) remove .git folders.. "
+find ./ -name '.git' | xargs rm -rf
+
+# Initialize Git repository
+if [ ! -d .git ]
+then
+  git init ./
+  git checkout -b tizen_gbs
+  git add ./
+  git commit -m "Initial commit"
+fi
+
+
+echo -e "\n(4) Patch for tizen.org... "
+patch -p1 < config/tizen/iotjs_tizen.patch
+cp -ra config/tizen/packaging .
+
index 8e38c72..c7dcb84 100644 (file)
@@ -19,6 +19,9 @@ void service_app_terminate(void *data)
 void service_app_control(app_control_h app_control, void *data)
 {
        // Todo: add your code here.
+
+       // Emit 'appControl' event to the JavaScript side.
+       iotjs_tizen_app_control_cb(app_control, data);
        return;
 }
 
index 37a02ab..06b3860 100644 (file)
@@ -24,8 +24,8 @@ The logical number might be different from the physical
 pin number of the board. The mapping is available
 in the documentation of a given board.
 
-On NuttX, the pin number is defined in target board
-module. For more information, please check the
+* On Tizen, the pin number is defined in [this documentation](../targets/tizen/SystemIO-Pin-Information-Tizen.md#gpio).
+* On NuttX, the pin number is defined in the documentation of the target board. For more information, please check the
 following list:
 [STM32F4-discovery](../targets/nuttx/stm32f4dis/IoT.js-API-Stm32f4dis.md#gpio-pin)
 
index 6aece5c..fe0f0f9 100644 (file)
@@ -18,6 +18,8 @@ The following shows I2C module APIs available for each platform.
 
 The I2C module supports the I2C protocol. I2C bus has two signals - SDA and SCL.
 
+* On Tizen, the bus number is defined in [this documentation](../targets/tizen/SystemIO-Pin-Information-Tizen.md#i2c).
+
 ### i2c.open(configuration, callback)
 * `configuration` {Object} Configuration for open I2CBus.
   * `device` {string} Device path. (only on Linux)
diff --git a/docs/api/IoT.js-API-MQTT.md b/docs/api/IoT.js-API-MQTT.md
new file mode 100644 (file)
index 0000000..2227097
--- /dev/null
@@ -0,0 +1,198 @@
+### Platform Support
+
+The following chart shows the availability of each TLS module API function on each platform.
+
+|  | Linux<br/>(Ubuntu) | Tizen<br/>(Raspberry Pi) | Raspbian<br/>(Raspberry Pi) | Nuttx<br/>(STM32F4-Discovery) | TizenRT<br/>(Artik053) |
+| :---: | :---: | :---: | :---: | :---: | :---: |
+| mqtt.getClient  | O | X | X | X | X | X |
+| mqtt.publish  | O | X | X | X | X | X |
+| mqtt.subscribe | O | X | X | X | X | X |
+| mqtt.unsubscribe | X | X | X | X | X | X |
+| mqtt.ping | O | X | X | X | X | X |
+| mqtt.connect | O | X | X | X | X | X |
+
+# MQTT
+
+MQTT is a machine-to-machine (M2M)/"Internet of Things" connectivity protocol. It was designed as an extremely lightweight publish/subscribe messaging transport. It is useful for connections with remote locations where a small code footprint is required and/or network bandwidth is at a premium.
+
+### QoS
+The QoS level can be 0, 1 or 2.
+- Level 0 means the packet arrives at most once.
+- Level 1 means the packet arrives at least once (duplications might occur, it is the user's responsibility to take care of them).
+- Level 2 means that the package is delivered exactly once.
+
+### Topic seperating and wildcarding
+Topics can be wildcarded and they also can be structured into multiple levels. These levels are divided by the `/` sign (eg. `iotjs/jerryscript/jerry-core`). There are multiple wildcarding possibilities:
+ - `Multi-level wildcard` The `#` sign is a wildcard character that matches any number of levels within a topic. This character MUST be the last character in a topic name. Typing `iotjs/#` means the client subscribes to anything that is under the `iotjs` topic.
+ - `Single-level wildcard` The `+` sign is a wildcard character that matches only one topic level. It can be used more at than one level in the topic name. It MUST be used so it occupies an entire level of the name. Typing `iotjs/+/jerry-core` subscribes you to `jerry-core` topic.
+ - Topics that are beginning with `$` can not be matched with wildcard filters such as `#` or `+`. Subscriptions with wildcards to these topics means that they receive no data at all.
+
+## Class: MQTTClient
+The `MQTTClient` can subscribe or publish data to a broker. It sends data over a `net.socket`.
+
+### mqtt.getClient(options)
+- `options` {Object}
+    -  `clientId` {Buffer | string} Optional. The broker identifies each client by its `clientId`. If not specified, a randomly generated `clientId` is created.
+    -  `host` {Buffer | string} The address of the broker.
+    -  `port` {number} The port of the broker.
+    - `username` {Buffer | string} Optional. Use username when onnecting to a broker.
+    - `password` {Buffer | string} Optional. Use password authentication when connecting to a broker.
+    - `keepalive` {number} Keepalive time in seconds. If no data is sent on the connection in the given time window the broker disconnects the client.
+    - `will` {boolean} Optional. If this flag is set to `true`, a `message` and a `topic` must follow with a QoS value between 0 and 2.
+    - `qos` {number} If `will` is set to `true`, the message will be sent with the given QoS.
+    - `topic` {Buffer | string} Only processed when `will` is set to `true`. The topic the `message` should be sent to.
+    - `message` {Buffer | string} Only processed when `will` is set to `true`. The message to be sent to the broker when connecting.
+
+Returns an MQTTClient.
+
+### mqtt.connect(callback)
+- `callback` {function} The function will be executed when the client successfuly connected to the broker.
+
+Connects the client to a broker. Emits a `connect` event.
+
+**Example**
+```js
+var mqtt = require('mqtt');
+
+var opts = {
+    host: '127.0.0.1',
+    port: 443,
+    keepalive: 10,
+    clientId: 'IoT.js Client',
+}
+
+var client = mqtt.getClient(opts);
+client.connect(function () {
+    client.disconnect();
+});
+```
+
+### mqtt.disconnect()
+Disconnects the client from the broker.
+
+### mqtt.ping()
+Sends a ping request to the server. If the server doesn't respond within 3 seconds, the client closes the connection. Emits a `pingresp` event if the server responded.
+
+**Example**
+```js
+var mqtt = require('mqtt');
+
+var opts = {
+    host: '127.0.0.1',
+    port: 443,
+    keepalive: 10,
+    clientId: 'IoT.js Client',
+}
+
+var client = mqtt.getClient(opts);
+client.connect(function () {
+    client.ping();
+});
+
+client.on('pingresp', function() {
+  client.disconnect();
+});
+```
+
+### mqtt.subscribe(options)
+- `options` {Object}
+    - `topic` {Buffer | string} The topic the client subscribes to.
+    - `qos` {number} Optional. Defaults to 0.
+    - `retain` {boolean} Optional. If retain is `true` the client receives the messages that were sent to the desired `topic` before it connected. Defaults to `false`.
+
+The client subscribes to a given `topic`. If there are messages available on the `topic` the client emits a `data` event with the message received from the broker.
+
+**Example**
+```js
+var mqtt = require('mqtt');
+
+var opts = {
+    host: '127.0.0.1',
+    port: 443,
+    keepalive: 10,
+    clientId: 'IoT.js Client',
+}
+
+var subscribe_opts {
+  topic: 'hello/#/iotjs',
+  retain: false,
+  qos: 2
+}
+
+var client = mqtt.getClient(opts);
+client.connect(function () {
+    client.subscribe(subscribe_opts);
+});
+
+client.on('data', function(data) {
+  console.log('I received something: ' + data.toString());
+});
+```
+
+### mqtt.unsubscribe(topic)
+- `options` {Buffer | string} The topic to unsubscribe from.
+
+Unsubscribes the client from a given topic. If QoS was turned on on the subscription the remaining packets will be sent by the server.
+
+
+### mqtt.publish(options)
+- `options` {Object}
+    - `topic` {Buffer | string} The topic to send the `message` to.
+    - `message` {Buffer | string} The message to be sent.
+    - `qos` {number} Optional. Defaults to 0.
+    - `retain` {boolean} Optional. If retain is `true` the broker stores the message for clients subscribing with retain `true` flag, therefore they can receive it later.
+
+Publishes a `message` to the broker under the given `topic`.
+
+**Example**
+```js
+var mqtt = require('mqtt');
+
+var opts = {
+    host: '127.0.0.1',
+    port: 443,
+    keepalive: 10,
+    clientId: 'IoT.js Client',
+}
+
+var publish_opts {
+  topic: 'hello/#/iotjs',
+  message: 'MQTT now works!',
+  retain: false,
+  qos: 1
+}
+
+var client = mqtt.getClient(opts);
+client.connect(function () {
+    client.publish(publish_opts);
+});
+```
+
+## Events
+### `connect`
+Emitted when the client successfully connects to a broker.
+
+### `disconnect`
+A `disconnect` event is emitted when the broker disconnects the client gracefully.
+
+### `error`
+If an error occured an `error` event is emitted with the error data.
+
+### `message`
+When data is received from the server a `message` event is emitted with a `data` object. It has the following properties:
+   - `message`: The message the broker sent.
+   - `topic`: The topic the message was sent from.
+   - `qos`: The QoS level the message was sent with.
+   - `packet_id`: The id of the packet if QoS was enabled.
+
+### `pingresp`
+Emitted when we receive a ping response from the server.
+
+### `puback`
+`puback` is emitted if the server has successfully received the QoS 1 packet sent with `publish`.
+
+### `pubcomp`
+If a QoS level 2 package has successfully arrived a `pubcomp` is emitted.
+
+### `suback`
+If a subscription was accepted by the broker to a topic, a `suback` event is emitted.
index 20d7342..62b22bd 100644 (file)
@@ -45,6 +45,10 @@ For each directory in search paths above:
 - Extra step for Linux/Tizen targets:
   - If a file with `id.iotjs` exists, try to load it as an IoT.js dynamic module and return.
 
+**Changing current working directory**
+
+You can explicitly change current working directory by setting `IOTJS_WORKING_DIR_PATH` environment variable. It is not recommended that you set this variable, if possible.
+
 **Adding extra paths for module loading**
 
 In order to add more directories to look for modules, you can set `IOTJS_EXTRA_MODULE_PATH` as an environment variable of your system. For instance, `./node_modules` and `./my_modules` will be referred if they're declared as follows.
index 4166249..7d56526 100644 (file)
@@ -47,6 +47,7 @@ The `env` property returns an object containing a few environment variables.
 The following environment elements can be accessed:
 * `HOME`
 * `IOTJS_PATH` which is set to `/mnt/sdcard` on NuttX by default.
+* `IOTJS_WORKING_DIR_PATH` is the specified current working directory path to change the root of the module load.
 * `IOTJS_EXTRA_MODULE_PATH` contains the paths to be additionally referenced to load any module.
 * `env` contains `'experimental'` if the IoT.js was build with experimental support.
 
index b214188..0fc3b9b 100644 (file)
@@ -16,7 +16,8 @@ The following shows spi module APIs available for each platform.
 
 SPI (Serial Peripheral Interface) is a communication protocol which defines a way to communicate between devices.
 
-On NuttX, you have to know the number of pins that is defined on the target board module. For more information, please see the list below.
+* On Tizen, the bus number is defined in [this documentation](../targets/tizen/SystemIO-Pin-Information-Tizen.md#spi).
+* On NuttX, you have to know the number of pins that is defined on the target board module. For more information, please see the list below.
   * [STM32F4-discovery](../targets/nuttx/stm32f4dis/IoT.js-API-Stm32f4dis.md)
 
 ### SPI.MODE
index c5d1e48..ab57210 100644 (file)
@@ -15,6 +15,8 @@ The following shows uart module APIs available for each platform.
 
 The UART (Universal Asynchronous Receiver/Transmitter) class supports asynchronous serial communication.
 
+* On Tizen, the port number is defined in [this documentation](../targets/tizen/SystemIO-Pin-Information-Tizen.md#uart).
+
 ### uart.open(configuration, callback)
 * `configuration` {Object}
   * `device` {string} Mandatory configuration. The specified device path.(Linux, Nuttx and TizenRT only)
diff --git a/docs/targets/tizen/SystemIO-Pin-Information-Tizen.md b/docs/targets/tizen/SystemIO-Pin-Information-Tizen.md
new file mode 100644 (file)
index 0000000..55b6cb9
--- /dev/null
@@ -0,0 +1,71 @@
+When you use System I/O module that is `GPIO`, `PWM`, `SPI`, `I2C`, and `UART`, you should know specified pin, bus or port number. 
+
+### GPIO
+
+#### ARTIK530
+| GPIO Name | Pin Number | GPIO Name | Pin Number |
+| :---: | :---: | :---: | :---: |
+| GPIO0 | 128 | GPIO1 | 129 |
+| GPIO2 | 130 | GPIO3 | 46 |
+| GPIO4 | 14 | GPIO5 | 41 |
+| GPIO6 | 25 | GPIO7 | 0 |
+| GPIO8 | 26 | GPIO9 | 27 |
+
+#### Raspberry Pi3
+| GPIO Name | Pin Number | GPIO Name | Pin Number |
+| :---: | :---: | :---: | :---: |
+| GPIO4 | 4 | GPIO5 | 5 |
+| GPIO6 | 6 | GPIO12 | 12 |
+| GPIO13 | 13 | GPIO16 | 16 |
+| GPIO17 | 17 | GPIO18 | 18 |
+| GPIO19 | 19 | GPIO20 | 20 |
+| GPIO21 | 21 | GPIO20 | 20 |
+| GPIO23 | 23 | GPIO24 | 24 |
+| GPIO25 | 25 | GPIO26 | 26 |
+| GPIO27 | 27 | - | - |
+
+
+### PWM
+
+#### ARTIK530
+| PWM Name | Pin Number |
+| :---: | :---: |
+| PWM0 | 2 |
+
+
+### SPI
+
+#### ARTIK530
+| SPI Name | Bus Number | Chip Select |
+| :---: | :---: | :---: |
+| SPI | 2 | 0 |
+
+#### Raspberry Pi3
+| SPI Name | Bus Number | Chip Select |
+| :---: | :---: | :---: |
+| SPI0(CS0) | 0 | 0 |
+| SPI0(CS1) | 0 | 1 |
+
+### I2C
+
+#### ARTIK530
+| I2C Name | Bus Number |
+| :---: | :---: |
+| I2C | 1 |
+
+#### Raspberry Pi3
+| I2C Name | Bus Number |
+| :---: | :---: |
+| I2C | 1 |
+
+#### UART
+
+#### ARTIK530
+| UART Name | Port Number |
+| :---: | :---: |
+| UART0 | 4 |
+
+#### Raspberry Pi3
+| UART Name | Port Number |
+| :---: | :---: |
+| UART0 | 0 |
\ No newline at end of file
index 9a4f66c..37a7ccd 100644 (file)
@@ -64,7 +64,7 @@ cat LICENSE
 cp %{SOURCE1001} .
 
 %build
-./tools/build.py \
+V=1 VERBOSE=1 ./tools/build.py \
   --clean \
   --buildtype=%{build_mode} \
   --profile=test/profiles/tizen.profile \
@@ -76,26 +76,23 @@ cp %{SOURCE1001} .
   --external-lib=dlog \
   --external-lib=bundle \
   --external-lib=capi-appfw-app-control \
+  --external-lib=appcore-agent \
+  --external-lib=pthread \
+  --external-lib=curl \
   --external-include-dir=/usr/include/dlog/ \
   --external-include-dir=/usr/include/appcore-agent/ \
   --external-include-dir=/usr/include/appfw/ \
   --external-include-dir=/usr/include/glib-2.0/ \
   --external-include-dir=/usr/lib/glib-2.0/include/ \
   --compile-flag=-D__TIZEN__ \
-  --compile-flag=-fPIC \
+  --compile-flag=-DENABLE_DEBUG_LOG \
   --jerry-cmake-param=-DENABLE_STATIC_LINK=OFF \
+  --create-shared-lib \
   --no-init-submodule \
   --no-parallel-build \
   %{external_build_options}
 # --external-lib=sdkapi \
 
-# Create shared library
-%define iotjs_target_lib libjerry-core.a libjerry-port-default.a libhttpparser.a libtuv.a \\\
-  libmbedx509.a libmbedtls.a libmbedcrypto.a libiotjs.a
-%define iotjs_lib_flag -lcapi-system-peripheral-io -lpthread -lcurl -ldlog -lappcore-agent -lcapi-appfw-app-common -lbundle -lcapi-appfw-app-control
-cd ./build/noarch-tizen/%{build_mode}/lib/
-gcc -shared -o libiotjs.so -Wl,--whole-archive %{iotjs_target_lib} -Wl,--no-whole-archive %{iotjs_lib_flag}
-
 %install
 mkdir -p %{buildroot}%{_bindir}
 mkdir -p %{buildroot}%{_includedir}/iotjs
index 6249fd2..72708a5 100644 (file)
@@ -39,7 +39,6 @@ void iotjs_bridge_sample_func(const char* command, const char* message,
   } else if (strncmp(command, "testThread", strlen("testThread")) == 0) {
     uv_thread_t thread1;
     uv_thread_create(&thread1, thread1_worker, return_handle);
-    uv_thread_join(&thread1);
   } else if (strncmp(command, "getResPath", strlen("getResPath")) == 0) {
     iotjs_bridge_set_msg(return_handle, "res/");
   } else {
diff --git a/samples/tizen-bridge-native/tizen_bridge_native.c b/samples/tizen-bridge-native/tizen_bridge_native.c
new file mode 100644 (file)
index 0000000..8ce585c
--- /dev/null
@@ -0,0 +1,52 @@
+/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors
+ *
+ * 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.
+ */
+
+#include "iotjs.h"
+#include "iotjs_tizen_service_app.h"
+
+/* thread */
+#include <pthread.h>
+#include <unistd.h>
+/* printf */
+#include <stdio.h>
+
+
+static void user_cb(int err, const char* data) {
+  printf("err: %d, data: %s\n", err, data);
+}
+
+
+void* thread(void* data) {
+  sleep(1);
+
+  char* str = "1234567A1234567B1234567C";
+  IOTJS_TIZEN_CALL_JFUNC("hello", "world", user_cb);
+  IOTJS_TIZEN_CALL_JFUNC("hello", str, user_cb);
+  IOTJS_TIZEN_CALL_JFUNC("hello", "", user_cb);
+  IOTJS_TIZEN_CALL_JFUNC("", "", user_cb);
+  IOTJS_TIZEN_CALL_JFUNC("", "", NULL);
+  IOTJS_TIZEN_CALL_JFUNC("notReturnString", "", user_cb);
+  return 0;
+}
+
+
+int main(int argc, char** argv) {
+  pthread_t tid;
+  if (pthread_create(&(tid), NULL, &thread, NULL)) {
+    return 1;
+  }
+
+  return iotjs_entry(argc, argv);
+}
similarity index 61%
rename from test/run_pass/issue/issue-1351.js
rename to samples/tizen-bridge-native/tizen_bridge_native.js
index afa4c73..0db23fa 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright 2017-present Samsung Electronics Co., Ltd. and other contributors
+/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * limitations under the License.
  */
 
-var assert = require('assert');
-var fs = require('fs');
+var tizen = require('tizen');
 
-var filePath = process.cwd() + '/resources';
+tizen.hello = function(data) {
+  return 'tizen.hello is called with data, ' + (data ? data : 'null');
+}
 
-try {
-  process.readSource(filePath);
-} catch (e) {
-  assert.equal(fs.existsSync(filePath), true);
-  assert.equal(e.name, 'Error');
-  assert.equal(e.message, 'ReadSource error, not a regular file');
+tizen.notReturnString = function(data) {
 }
+
+setInterval(function() {
+  console.log('heartbeat');
+}, 10000);
diff --git a/sonar-project.properties b/sonar-project.properties
new file mode 100644 (file)
index 0000000..9a74a10
--- /dev/null
@@ -0,0 +1,5 @@
+sonar.projectKey=samsung.iot.js
+sonar.projectName=IoT.js
+sonar.projectVersion=1.0
+sonar.sources=src
+sonar.cfamily.build-wrapper-output=bw-output
index 52187a0..b4ba182 100644 (file)
@@ -23,6 +23,9 @@
 #define IOTJS_MAGIC_STRING_3 "3"
 #endif
 #define IOTJS_MAGIC_STRING_ABORT "abort"
+#if ENABLE_MODULE_MQTT
+#define IOTJS_MAGIC_STRING_ACKTYPE "type"
+#endif
 #if ENABLE_MODULE_ADC
 #define IOTJS_MAGIC_STRING_ADC "Adc"
 #endif
@@ -74,6 +77,9 @@
 #define IOTJS_MAGIC_STRING_CHIPSELECT "chipSelect"
 #define IOTJS_MAGIC_STRING_CHIPSELECT_U "CHIPSELECT"
 #endif
+#if ENABLE_MODULE_MQTT
+#define IOTJS_MAGIC_STRING_CLIENTID "clientId"
+#endif
 #define IOTJS_MAGIC_STRING_CLOSE "close"
 #define IOTJS_MAGIC_STRING_CLOSESYNC "closeSync"
 #define IOTJS_MAGIC_STRING_CODE "code"
 #define IOTJS_MAGIC_STRING_DIRECTION "direction"
 #define IOTJS_MAGIC_STRING_DIRECTION_U "DIRECTION"
 #endif
+#ifdef ENABLE_MODULE_MQTT
+#define IOTJS_MAGIC_STRING_DISCONNECT "disconnect"
+#endif
 #define IOTJS_MAGIC_STRING_DOEXIT "doExit"
 #if ENABLE_MODULE_UDP
 #define IOTJS_MAGIC_STRING_DROPMEMBERSHIP "dropMembership"
 #define IOTJS_MAGIC_STRING_IOTJS_ENV_U "IOTJS_ENV"
 #define IOTJS_MAGIC_STRING_IOTJS_PATH_U "IOTJS_PATH"
 #define IOTJS_MAGIC_STRING_IOTJS_EXTRA_MODULE_PATH_U "IOTJS_EXTRA_MODULE_PATH"
+#define IOTJS_MAGIC_STRING_IOTJS_WORKING_DIR_PATH_U "IOTJS_WORKING_DIR_PATH"
 #define IOTJS_MAGIC_STRING_IOTJS "iotjs"
 #define IOTJS_MAGIC_STRING_IPV4 "IPv4"
 #define IOTJS_MAGIC_STRING_IPV6 "IPv6"
 #if ENABLE_MODULE_TLS
 #define IOTJS_MAGIC_STRING_ISSERVER "isServer"
 #endif
+#if ENABLE_MODULE_MQTT
+#define IOTJS_MAGIC_STRING_KEEPALIVE "keepalive"
+#endif
 #define IOTJS_MAGIC_STRING_KEY "key"
 #define IOTJS_MAGIC_STRING_LENGTH "length"
 #define IOTJS_MAGIC_STRING_LISTEN "listen"
 #define IOTJS_MAGIC_STRING_LSB "LSB"
 #define IOTJS_MAGIC_STRING_MAXSPEED "maxSpeed"
 #endif
+#if ENABLE_MODULE_MQTT
+#define IOTJS_MAGIC_STRING_MESSAGE "message"
+#endif
 #define IOTJS_MAGIC_STRING_METHOD "method"
 #define IOTJS_MAGIC_STRING_METHODS "methods"
 #define IOTJS_MAGIC_STRING_MKDIR "mkdir"
 #if ENABLE_MODULE_SPI || ENABLE_MODULE_GPIO
 #define IOTJS_MAGIC_STRING_MODE_U "MODE"
 #endif
+#if ENABLE_MODULE_MQTT
+#define IOTJS_MAGIC_STRING_MQTTINIT "MqttInit"
+#define IOTJS_MAGIC_STRING_MQTTMESSAGE "MqttMessage"
+#define IOTJS_MAGIC_STRING_MQTTHANDLE "MqttHandle"
+#endif
 #if ENABLE_MODULE_SPI
 #define IOTJS_MAGIC_STRING_MSB "MSB"
 #endif
 #define IOTJS_MAGIC_STRING_ONBODY "OnBody"
 #define IOTJS_MAGIC_STRING_ONCLOSE "onclose"
 #define IOTJS_MAGIC_STRING_ONCLOSED "onClosed"
+#if ENABLE_MODULE_MQTT
+#define IOTJS_MAGIC_STRING__ONCONNECT "_onconnect"
+#endif
 #define IOTJS_MAGIC_STRING_ONCONNECTION "onconnection"
 #define IOTJS_MAGIC_STRING_ONDATA "onData"
+#ifdef ENABLE_MODULE_MQTT
+#define IOTJS_MAGIC_STRING__ONDISCONNECT "_ondisconnect"
+#endif
 #define IOTJS_MAGIC_STRING_ONEND "onEnd"
 #define IOTJS_MAGIC_STRING_ONERROR "onError"
 #if ENABLE_MODULE_TLS
 #define IOTJS_MAGIC_STRING_ONHEADERSCOMPLETE "OnHeadersComplete"
 #define IOTJS_MAGIC_STRING_ONHEADERS "OnHeaders"
 #define IOTJS_MAGIC_STRING_ONMESSAGECOMPLETE "OnMessageComplete"
+#if ENABLE_MODULE_MQTT
+#define IOTJS_MAGIC_STRING__ONMESSAGE "_onmessage"
+#endif
 #define IOTJS_MAGIC_STRING_ONMESSAGE "onmessage"
 #define IOTJS_MAGIC_STRING__ONNEXTTICK "_onNextTick"
+#if ENABLE_MODULE_MQTT
+#define IOTJS_MAGIC_STRING__ONPINGRESP "_onpingresp"
+#define IOTJS_MAGIC_STRING__ONPUBACK "_onpuback"
+#define IOTJS_MAGIC_STRING__ONPUBCOMP "_onpubcomp"
+#define IOTJS_MAGIC_STRING__ONPUBREC "_onpubrec"
+#define IOTJS_MAGIC_STRING__ONPUBREL "_onpubrel"
+#endif
 #define IOTJS_MAGIC_STRING_ONREAD "onread"
 #define IOTJS_MAGIC_STRING_ONSOCKET "onSocket"
+#if ENABLE_MODULE_MQTT
+#define IOTJS_MAGIC_STRING__ONSUBACK "_onsuback"
+#define IOTJS_MAGIC_STRING__ONUNSUBACK "_onunsuback"
+#endif
 #define IOTJS_MAGIC_STRING_ONTIMEOUT "onTimeout"
 #define IOTJS_MAGIC_STRING__ONUNCAUGHTEXCEPTION "_onUncaughtException"
 #if ENABLE_MODULE_TLS
 #define IOTJS_MAGIC_STRING_OUT_U "OUT"
 #endif
 #define IOTJS_MAGIC_STRING_OWNER "owner"
+#if ENABLE_MODULE_MQTT
+#define IOTJS_MAGIC_STRING_PACKETID "packet_id"
+#define IOTJS_MAGIC_STRING_PASSWORD "password"
+#endif
 #define IOTJS_MAGIC_STRING_PAUSE "pause"
 #define IOTJS_MAGIC_STRING_PERIOD "period"
 #define IOTJS_MAGIC_STRING_PIN "pin"
+#if ENABLE_MODULE_MQTT
+#define IOTJS_MAGIC_STRING_PING "ping"
+#endif
 #define IOTJS_MAGIC_STRING_PLATFORM "platform"
 #define IOTJS_MAGIC_STRING_PORT "port"
+#define IOTJS_MAGIC_STRING_PRIVATE "_private"
 #define IOTJS_MAGIC_STRING_PROTOTYPE "prototype"
+#if ENABLE_MODULE_MQTT
+#define IOTJS_MAGIC_STRING_PUBLISH "publish"
+#endif
 #if ENABLE_MODULE_GPIO
 #define IOTJS_MAGIC_STRING_PULLDOWN_U "PULLDOWN"
 #define IOTJS_MAGIC_STRING_PULLUP_U "PULLUP"
 #define IOTJS_MAGIC_STRING_PUSHPULL_U "PUSHPULL"
 #endif
+#if ENABLE_MODULE_MQTT
+#define IOTJS_MAGIC_STRING_QOS "qos"
+#endif
 #define IOTJS_MAGIC_STRING_READDIR "readdir"
 #define IOTJS_MAGIC_STRING_READ "read"
 #define IOTJS_MAGIC_STRING_READSOURCE "readSource"
 #define IOTJS_MAGIC_STRING_REQUEST_U "REQUEST"
 #define IOTJS_MAGIC_STRING_RESPONSE_U "RESPONSE"
 #define IOTJS_MAGIC_STRING_RESUME "resume"
+#if ENABLE_MODULE_MQTT
+#define IOTJS_MAGIC_STRING_RETAIN "retain"
+#endif
 #define IOTJS_MAGIC_STRING__REUSEADDR "_reuseAddr"
 #if ENABLE_MODULE_GPIO
 #define IOTJS_MAGIC_STRING_RISING_U "RISING"
 #endif
 #define IOTJS_MAGIC_STRING_RMDIR "rmdir"
 #define IOTJS_MAGIC_STRING_SEND "send"
+#if ENABLE_MODULE_MQTT
+#define IOTJS_MAGIC_STRING_SENDACK "sendAck"
+#endif
 #define IOTJS_MAGIC_STRING_SENDREQUEST "sendRequest"
 #if ENABLE_MODULE_TLS
 #define IOTJS_MAGIC_STRING_SERVERNAME "servername"
 #define IOTJS_MAGIC_STRING_STDERR "stderr"
 #define IOTJS_MAGIC_STRING_STDOUT "stdout"
 #define IOTJS_MAGIC_STRING_STOP "stop"
+#if ENABLE_MODULE_MQTT
+#define IOTJS_MAGIC_STRING_SUBSCRIBE "subscribe"
+#endif
 #if ENABLE_MODULE_TLS
 #define IOTJS_MAGIC_STRING_TLSSOCKET "TLSSocket"
 #define IOTJS_MAGIC_STRING_TLSCONTEXT "TlsContext"
 #define IOTJS_MAGIC_STRING_TLSINIT "TlsInit"
 #endif
+#if ENABLE_MODULE_MQTT
+#define IOTJS_MAGIC_STRING_TOPIC "topic"
+#endif
 #define IOTJS_MAGIC_STRING_TOSTRING "toString"
 #if ENABLE_MODULE_SPI
 #define IOTJS_MAGIC_STRING_TRANSFER "transfer"
 #endif
 #define IOTJS_MAGIC_STRING_UNLINK "unlink"
 #define IOTJS_MAGIC_STRING_UNREF "unref"
+#if ENABLE_MODULE_MQTT
+#define IOTJS_MAGIC_STRING_UNSUBSCRIBE "unsubscribe"
+#endif
 #define IOTJS_MAGIC_STRING_UPGRADE "upgrade"
+#if ENABLE_MODULE_MQTT
+#define IOTJS_MAGIC_STRING_USERNAME "username"
+#endif
 #define IOTJS_MAGIC_STRING_URL "url"
 #define IOTJS_MAGIC_STRING_VERSION "version"
+#if ENABLE_MODULE_MQTT
+#define IOTJS_MAGIC_STRING_WILL "will"
+#endif
 #define IOTJS_MAGIC_STRING_WRITEUINT8 "writeUInt8"
 #define IOTJS_MAGIC_STRING_WRITE "write"
 #define IOTJS_MAGIC_STRING_WRITEDECODE "writeDecode"
index 243ee6b..abd7a86 100644 (file)
@@ -25,6 +25,8 @@
 #include <execinfo.h>
 #endif
 
+void force_terminate();
+
 iotjs_string_t iotjs_file_read(const char* path) {
   FILE* file = fopen(path, "rb");
   if (file == NULL) {
@@ -40,6 +42,13 @@ iotjs_string_t iotjs_file_read(const char* path) {
   fseek_ret = fseek(file, 0, SEEK_SET);
   IOTJS_ASSERT(fseek_ret == 0);
 
+  if (ftell_ret < 0 || fseek_ret != 0) {
+    iotjs_string_t empty_content = iotjs_string_create();
+    fclose(file);
+    DLOG("iotjs_file_read error");
+    return empty_content;
+  }
+
   char* buffer = iotjs_buffer_allocate(len + 1);
 
 #if defined(__NUTTX__) || defined(__TIZENRT__)
@@ -68,7 +77,10 @@ iotjs_string_t iotjs_file_read(const char* path) {
 
 char* iotjs_buffer_allocate(size_t size) {
   char* buffer = (char*)(calloc(size, sizeof(char)));
-  IOTJS_ASSERT(buffer != NULL);
+  if (buffer == NULL) {
+    DLOG("Out of memory");
+    force_terminate();
+  }
   return buffer;
 }
 
@@ -87,7 +99,12 @@ char* iotjs_buffer_allocate_from_number_array(size_t size,
 
 char* iotjs_buffer_reallocate(char* buffer, size_t size) {
   IOTJS_ASSERT(buffer != NULL);
-  return (char*)(realloc(buffer, size));
+  char* newbuffer = (char*)(realloc(buffer, size));
+  if (newbuffer == NULL) {
+    DLOG("Out of memmory");
+    force_terminate();
+  }
+  return newbuffer;
 }
 
 
index 9574b69..adccee2 100644 (file)
@@ -32,6 +32,9 @@ void iotjs_buffer_release(char* buff);
 #define IOTJS_ALLOC(type) /* Allocate (type)-sized, (type*)-typed memory */ \
   (type*)iotjs_buffer_allocate(sizeof(type))
 
+#define IOTJS_CALLOC(num, type) \
+  (type*)iotjs_buffer_allocate((num * sizeof(type)))
+
 #define IOTJS_RELEASE(ptr) /* Release memory allocated by IOTJS_ALLOC() */ \
   ({                                                                       \
     iotjs_buffer_release((char*)ptr);                                      \
index 01c029f..7d51be3 100644 (file)
     this.exports = {};
   }
 
-
   Module.cache = {};
+  Module.builtin_modules = {};
 
+  mixin(Module.builtin_modules, process.builtin_modules);
+  mixin(Module, process._private);
+  process._private = undefined;
 
   Module.require = function(id) {
-    if (id == 'native') {
+    if (id === 'builtin') {
       return Module;
     }
 
@@ -44,7 +47,7 @@
 
 
   Module.prototype.compile = function() {
-    process.compileModule(this, Module.require);
+    Module.compileModule(this, Module.require);
   };
 
 
 
   EventEmitter.call(process);
 
-  var keys = Object.keys(EventEmitter.prototype);
-  var keysLength = keys.length;
-  for (var i = 0; i < keysLength; ++i) {
-    var key = keys[i];
-    if (!process[key]) {
-      process[key] = EventEmitter.prototype[key];
+  mixin(process, EventEmitter.prototype);
+
+  function mixin(target, source) {
+    for (var prop in source) {
+      if (source.hasOwnProperty(prop) && !target[prop]) {
+        target[prop] = source[prop];
+      }
     }
   }
 
index 3a1620c..5627804 100644 (file)
@@ -14,8 +14,9 @@
  */
 
 
-var Native = require('native');
-var fs = Native.require('fs');
+var Builtin = require('builtin');
+var fs = Builtin.require('fs');
+var dynamicloader = Builtin.require('dynamicloader');
 
 function Module(id, parent) {
   this.id = id;
@@ -31,13 +32,12 @@ Module.cache = {};
 // Cache to store not yet compiled remote modules
 Module.remoteCache = {};
 
+var moduledirs = [''];
 
 var cwd;
 try {
-  cwd = process.cwd();
+  cwd = process.env.IOTJS_WORKING_DIR_PATH || process.cwd();
 } catch (e) { }
-
-var moduledirs = [''];
 if (cwd) {
   moduledirs.push(cwd + '/');
   moduledirs.push(cwd + '/iotjs_modules/');
@@ -61,8 +61,6 @@ if (process.env.IOTJS_EXTRA_MODULE_PATH) {
   });
 }
 
-var dynamicloader = Native.require('dynamicloader');
-
 function tryPath(modulePath, ext) {
   return Module.tryPath(modulePath) ||
          Module.tryPath(modulePath + ext);
@@ -106,7 +104,7 @@ Module.resolveFilepath = function(id, directories) {
     var jsonpath = modulePath + '/package.json';
 
     if (Module.tryPath(jsonpath)) {
-      var pkgSrc = process.readSource(jsonpath);
+      var pkgSrc = Builtin.readSource(jsonpath);
       var pkgMainFile = JSON.parse(pkgSrc).main;
 
       // pkgmain[.ext]
@@ -190,8 +188,8 @@ Module.tryPath = function(path) {
 
 
 Module.load = function(id, parent) {
-  if (process.builtin_modules[id]) {
-    return Native.require(id);
+  if (Builtin.builtin_modules[id]) {
+    return Builtin.require(id);
   }
   if (Module.remoteCache[id]) {
     Module.compileRemoteSource(id, Module.remoteCache[id]);
@@ -219,10 +217,10 @@ Module.load = function(id, parent) {
   var source;
 
   if (ext === 'js') {
-    source = process.readSource(modPath);
+    source = Builtin.readSource(modPath);
     module.compile(modPath, source);
   } else if (ext === 'json') {
-    source = process.readSource(modPath);
+    source = Builtin.readSource(modPath);
     module.exports = JSON.parse(source);
   } else if (dynamicloader && ext === 'iotjs') {
     module.exports = dynamicloader(modPath);
@@ -250,14 +248,14 @@ Module.compileRemoteSource = function(filename, source) {
 
 
 Module.prototype.compile = function(filename, source) {
-    var fn = process.compile(filename, source);
+    var fn = Builtin.compile(filename, source);
     fn.call(this.exports, this.exports, this.require.bind(this), this);
 };
 
 
 Module.runMain = function() {
-  if (process.debuggerWaitSource) {
-    var sources = process.debuggerGetSource();
+  if (Builtin.debuggerWaitSource) {
+    var sources = Builtin.debuggerGetSource();
     sources.forEach(function(rModule) {
       Module.remoteCache[rModule[0]] = rModule[1];
     });
diff --git a/src/js/mqtt.js b/src/js/mqtt.js
new file mode 100644 (file)
index 0000000..77c8ef2
--- /dev/null
@@ -0,0 +1,337 @@
+/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors
+ *
+ * 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.
+ */
+
+var net = require('net');
+var util = require('util');
+var EventEmitter = require('events').EventEmitter;
+
+util.inherits(MQTTClient, EventEmitter);
+
+var PacketTypeEnum = {
+  PUBACK: 4,
+  PUBREC: 5,
+  PUBREL: 6,
+  PUBCOMP: 7,
+};
+
+function MQTTClient(options) {
+  if (!(this instanceof MQTTClient)) {
+    return new MQTTClient(options);
+  }
+
+  EventEmitter.call(this);
+
+  this._clientOptions = Object.create(options, {
+    host: { value: options.host || '127.0.0.1'},
+    port: { value: options.port || 8883 },
+    qos: { value: options.qos || 0 },
+    keepalive: { value: options.keepalive || 60 },
+  });
+
+  this._socket = options.socket || new net.Socket();
+  this._socket.on('error', onerror);
+
+  this._isConnected = false;
+  this._reconnecting = false;
+  this._package_id = 0;
+
+  // Set the native callbacks
+  this._onconnect = onconnect;
+  this._ondisconnect = ondisconnect;
+  this._onmessage = onmessage;
+  this._onpingresp = onpingresp;
+  this._onpuback = onpuback;
+  this._onpubcomp = onpubcomp;
+  this._onpubrec = onpubrec;
+  this._onpubrel = onpubrel;
+  this._onsuback = onsuback;
+}
+
+/*
+ * Connect to an MQTT broker.
+ */
+function MqttConnect(socket, options) {
+  var buff = native.connect(options);
+  socket.write(buff);
+}
+
+MQTTClient.prototype.connect = function(callback) {
+  this._clientOptions.cb = callback;
+  var jsref = this;
+  if (this._socket instanceof net.Socket) {
+    this._socket = net.connect(this._clientOptions);
+    this._socket.on('connect', function() {
+      MqttConnect(this, jsref._clientOptions);
+    });
+  }
+
+  if (util.isFunction(callback)) {
+    this.on('connect', callback);
+  }
+
+  this._socket.on('data', function(data) {
+    ondata(jsref, data);
+  });
+  this._socket.on('error', function(e) {
+    jsref.emit('error', e);
+  });
+  this._socket.on('end', function() {
+    ondisconnect(jsref);
+  });
+};
+
+MQTTClient.prototype.disconnect = function(error) {
+  if (error) {
+    this.emit('error', error);
+  }
+
+  this._isConnected = false;
+  var buf = native.disconnect();
+  this._socket.write(buf);
+  this._socket.end();
+};
+
+MQTTClient.prototype.reconnect = function() {
+  if (this._reconnecting) {
+    return;
+  }
+
+  this.disconnect();
+  setTimeout(this.connect, this._options.reconnectPeriod);
+};
+
+MQTTClient.prototype.publish = function(options) {
+  if (!Buffer.isBuffer(options.message)) {
+    options.message = new Buffer(options.message);
+  }
+  if (!Buffer.isBuffer(options.topic)) {
+    options.topic = new Buffer(options.topic);
+  }
+
+  if (util.isNumber(options.qos) && options.qos > 0) {
+    options.packet_id = this._package_id;
+    this._package_id++;
+
+    var buffer = native.publish(options);
+    this._socket.write(buffer);
+
+    var self = this;
+
+    var interval = setInterval(function() {
+      self._socket.write(buffer);
+    }, 3000);
+
+    this.on('puback', function() {
+      clearInterval(interval);
+    });
+    this.on('pubrec', function() {
+      clearInterval(interval);
+    });
+
+    return;
+  }
+
+  this._socket.write(native.publish(options));
+};
+
+MQTTClient.prototype.subscribe = function(options) {
+  if (!Buffer.isBuffer(options.topic)) {
+    options.topic = new Buffer(options.topic);
+  }
+
+  var buff = native.subscribe(options);
+  this._socket.write(buff);
+};
+
+MQTTClient.prototype.ping = function() {
+  var buff = native.ping();
+  this._socket.write(buff);
+};
+
+MQTTClient.prototype.unsubscribe = function(topic) {
+  if (!Buffer.isBuffer(topic)) {
+    topic = new Buffer(topic);
+  }
+
+  var buf = native.unsubscribe(topic);
+  this._socket.write(buf);
+};
+
+MQTTClient.prototype.sendAcknowledge = function(options) {
+  var buff = native.sendAck(options);
+  this._socket.write(buff);
+};
+
+function onpubcomp(jsref, data) {
+  /*
+   * Qos level 2
+   * Handle PUBCOMP package. If this package is arrived, the sending process
+   * is done.
+   */
+  jsref.emit('pubcomp', data);
+}
+
+function onpubrel(jsref, data) {
+  /*
+   * Qos level 2
+   * Handle PUBREL package. If this package is arrived, we have to send back
+   * a PUBCOMP package to the server.
+   */
+  var options = {
+    type: PacketTypeEnum.PUBCOMP,
+    packet_id: data,
+  };
+
+  jsref.sendAcknowledge(options);
+}
+
+function ondata(jsref, data) {
+  var ret_val = native.MqttHandle(jsref, data);
+  if (ret_val instanceof Error) {
+    jsref.disconnect();
+    onerror(jsref, ret_val);
+  }
+}
+
+function onconnect(jsref) {
+  jsref.emit('connect');
+}
+
+function onpingresp(jsref) {
+  jsref.emit('pingresp');
+}
+
+function onmessage(jsref, message, topic, qos, packet_id) {
+  var data = {
+    message: message,
+    topic: topic,
+    qos: qos,
+    packet_id: packet_id,
+  };
+
+  if (qos == 1) {
+    var opts = {
+      type: PacketTypeEnum.PUBACK,
+      packet_id: packet_id,
+    };
+
+    jsref.sendAcknowledge(opts);
+  } else if (qos == 2) {
+    var options = {
+      type: PacketTypeEnum.PUBREC,
+      packet_id: packet_id,
+    };
+    jsref.sendAcknowledge(options);
+  }
+
+  jsref.emit('message', data);
+}
+
+function ondisconnect(jsref, message) {
+  jsref._isConnected = false;
+  jsref.emit('disconnect', message);
+}
+
+function onpuback(jsref, data) {
+  /*
+   * QoS level 1
+   * Handle PUBACK package. If this package isn't arrived (properly),
+   * we have to resend the last message.
+   *
+   * The 'data' contains the packet identifier.
+   */
+
+  jsref.emit('puback', data);
+}
+
+function onpubrec(jsref, data) {
+  /*
+   * Qos level 2
+   * Handle PUBREC package. If this package is arrived, we have to send back
+   * a PUBREL package to the server.
+   */
+  var options = {
+    type: PacketTypeEnum.PUBREL,
+    packet_id: data,
+  };
+
+  jsref.sendAcknowledge(options);
+
+  var interval = setInterval(function() {
+    jsref.sendAcknowledge(options);
+  }, 3000);
+
+  jsref.on('pubcomp', function() {
+    clearInterval(interval);
+  });
+
+  jsref.emit('pubrec', data);
+}
+
+function onsuback(jsref, data) {
+  /*
+   * Successful subscription, the client will get messages from the requested
+   * topic. The granted QoS is given in data.
+   */
+   jsref.emit('suback', data);
+}
+
+function onerror(jsref, error) {
+  jsref.emit('error', error);
+}
+
+/*
+ * Returns an unique client ID based on current time.
+ */
+function defaultClientId() {
+  return 'iotjs_mqtt_client_' + Date.now();
+}
+
+function getClient(connectOptions) {
+  if (util.isUndefined(connectOptions.clientId)) {
+    connectOptions.clientId = defaultClientId();
+  }
+  if (!Buffer.isBuffer(connectOptions.clientId)) {
+    connectOptions.clientId =
+        new Buffer(connectOptions.clientId.toString());
+  }
+  if (!util.isUndefined(connectOptions.username) &&
+      !Buffer.isBuffer(connectOptions.username)) {
+    connectOptions.username = new Buffer(connectOptions.username.toString());
+  }
+  if (!util.isUndefined(connectOptions.password) &&
+      !Buffer.isBuffer(connectOptions.password)) {
+    connectOptions.password = new Buffer(connectOptions.password.toString());
+  }
+  if (connectOptions.will) {
+    if (util.isUndefined(connectOptions.topic) ||
+        util.isUndefined(connectOptions.message) ||
+        connectOptions.qos < 0 || connectOptions.qos > 2) {
+      throw new Error('Wrong options given! Please refer to the documentation');
+    }
+
+    if (!util.isUndefined(connectOptions.topic) &&
+        !Buffer.isBuffer(connectOptions.topic)) {
+      connectOptions.topic = new Buffer(connectOptions.topic.toString());
+    }
+    if (!util.isUndefined(connectOptions.message) &&
+        !Buffer.isBuffer(connectOptions.message)) {
+      connectOptions.message = new Buffer(connectOptions.message.toString());
+    }
+  }
+  return new MQTTClient(connectOptions);
+}
+
+exports.getClient = getClient;
index 566011c..ccce784 100644 (file)
@@ -134,7 +134,7 @@ function launchAppControl(option) {
 
 
 var getResPath = function() {
-  return this.bridge.sendSync('getResPath', '');
+  return bridge.sendSync('getResPath', '');
 };
 
 
index f11a667..9454159 100644 (file)
       "js_file": "js/module.js",
       "require": ["fs"]
     },
+    "mqtt": {
+      "js_file": "js/mqtt.js",
+      "require": ["events", "util", "url"],
+      "native_files": ["modules/iotjs_module_mqtt.c"],
+      "init": "InitMQTT"
+    },
     "net": {
       "js_file": "js/net.js",
       "require": ["assert", "events", "stream", "tcp", "util"]
index 909e8d4..f8dadb7 100644 (file)
@@ -323,6 +323,7 @@ void after_worker(uv_work_t* req, int status) {
   } else {
     uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get());
     uv_async_t* async = IOTJS_ALLOC(uv_async_t);
+    bridgecall->async = async;
     async->data = (void*)bridgecall;
     uv_async_init(loop, async, aysnc_callback);
     uv_mutex_unlock(&bridgecall->call_lock);
index a393375..d0e264c 100644 (file)
@@ -159,11 +159,16 @@ JS_FUNCTION(ReadSync) {
 
   JS_GET_REQUIRED_ARG_VALUE(0, i2c->buf_len, IOTJS_MAGIC_STRING_LENGTH, number);
 
-  if (!iotjs_i2c_read(i2c)) {
-    return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kI2cOpRead));
+  jerry_value_t result;
+  if (iotjs_i2c_read(i2c)) {
+    result = iotjs_jval_create_byte_array(i2c->buf_len, i2c->buf_data);
+  } else {
+    result = JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kI2cOpRead));
   }
 
-  return iotjs_jval_create_byte_array(i2c->buf_len, i2c->buf_data);
+  IOTJS_RELEASE(i2c->buf_data);
+
+  return result;
 }
 
 jerry_value_t InitI2c() {
diff --git a/src/modules/iotjs_module_mqtt.c b/src/modules/iotjs_module_mqtt.c
new file mode 100644 (file)
index 0000000..58d0ef9
--- /dev/null
@@ -0,0 +1,798 @@
+/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors
+ *
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "iotjs_def.h"
+#include "iotjs_module_buffer.h"
+#include "iotjs_module_mqtt.h"
+
+
+#include "iotjs_handlewrap.h"
+#include "iotjs_reqwrap.h"
+
+
+static jerry_value_t mqtt_client_connack_error(const unsigned char error_code) {
+  switch (error_code) {
+    case UNACCEPTABLE_PROTOCOL:
+      return JS_CREATE_ERROR(COMMON,
+                             "MQTT: Connection refused: unacceptable protocol");
+    case BAD_IDENTIFIER:
+      return JS_CREATE_ERROR(COMMON,
+                             "MQTT: Connection refused: bad client identifier");
+    case SERVER_UNAVIABLE:
+      return JS_CREATE_ERROR(COMMON,
+                             "MQTT: Connection refused: server unaviable");
+    case BAD_CREDENTIALS:
+      return JS_CREATE_ERROR(
+          COMMON, "MQTT: Connection refused: bad username or password");
+    case UNAUTHORISED:
+      return JS_CREATE_ERROR(COMMON, "MQTT: Connection refused: unauthorised");
+    default:
+      return JS_CREATE_ERROR(COMMON, "MQTT: Unknown error");
+  }
+}
+
+
+static uint8_t *iotjs_encode_remaining_length(unsigned char *buffer,
+                                              uint32_t len) {
+  size_t rc = 0;
+  do {
+    unsigned char d = len & 0x7F;
+    len >>= 7;
+    if (len > 0) {
+      d |= 0x80;
+    }
+    buffer[rc++] = d;
+  } while (len > 0);
+
+  return (buffer + rc);
+}
+
+
+static size_t get_remaining_length_size(uint32_t len) {
+  uint8_t n = 0;
+  while (len != 0) {
+    len >>= 7;
+    n++;
+  }
+
+  return n;
+}
+
+
+static uint32_t iotjs_decode_remaining_length(char *buffer, size_t *offset) {
+  unsigned char c;
+  uint32_t remaining_length = 0;
+  uint32_t length = 0;
+  uint32_t shift = 0;
+
+  do {
+    if (++length > IOTJS_MODULE_MQTT_MAX_REMAINING_LENGTH_BYTES) {
+      return UINT32_MAX;
+    }
+    c = (unsigned char)buffer[*offset];
+    remaining_length += (uint32_t)(c & 0x7F) << shift;
+    shift += 7;
+
+    (*offset)++;
+  } while ((c & 128) != 0);
+
+  return remaining_length;
+}
+
+
+static uint16_t iotjs_mqtt_calculate_length(uint8_t msb, uint8_t lsb) {
+  return (msb << 8) | lsb;
+}
+
+
+static uint8_t *iotjs_mqtt_string_serialize(uint8_t *dst_buffer,
+                                            iotjs_bufferwrap_t *src_buffer) {
+  uint16_t len = src_buffer->length;
+  dst_buffer[0] = (uint8_t)(len >> 8);
+  dst_buffer[1] = (uint8_t)(len & 0x00FF);
+  memcpy(dst_buffer + 2, src_buffer->buffer, src_buffer->length);
+  return (dst_buffer + 2 + src_buffer->length);
+}
+
+void iotjs_create_ack_callback(char *buffer, char *name, jerry_value_t jsref) {
+  uint8_t packet_identifier_MSB = (uint8_t)buffer[2];
+  uint8_t packet_identifier_LSB = (uint8_t)buffer[3];
+
+  uint16_t package_id =
+      iotjs_mqtt_calculate_length(packet_identifier_MSB, packet_identifier_LSB);
+
+  // The callback takes the packet identifier as parameter.
+  iotjs_jargs_t args = iotjs_jargs_create(2);
+  iotjs_jargs_append_jval(&args, jsref);
+  iotjs_jargs_append_number(&args, package_id);
+
+  jerry_value_t fn = iotjs_jval_get_property(jsref, name);
+  iotjs_make_callback(fn, jsref, &args);
+  jerry_release_value(fn);
+  iotjs_jargs_destroy(&args);
+}
+
+
+JS_FUNCTION(MqttConnect) {
+  DJS_CHECK_THIS();
+
+  DJS_CHECK_ARGS(1, object);
+
+  jerry_value_t joptions = JS_GET_ARG(0, object);
+
+  jerry_value_t jclient_id =
+      iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_CLIENTID);
+  jerry_value_t jusername =
+      iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_USERNAME);
+  jerry_value_t jpassword =
+      iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_PASSWORD);
+  jerry_value_t jkeepalive =
+      iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_KEEPALIVE);
+  jerry_value_t jwill =
+      iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_WILL);
+  jerry_value_t jqos =
+      iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_QOS);
+  jerry_value_t jmessage =
+      iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_MESSAGE);
+  jerry_value_t jtopic =
+      iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_TOPIC);
+  jerry_value_t jretain =
+      iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_TOPIC);
+
+  uint8_t connect_flags = 0;
+  uint8_t keep_alive_msb = 0;
+  uint8_t keep_alive_lsb = 10;
+  connect_flags |= MQTT_FLAG_CLEANSESSION;
+  iotjs_bufferwrap_t *username = NULL;
+  iotjs_bufferwrap_t *password = NULL;
+  iotjs_bufferwrap_t *message = NULL;
+  iotjs_bufferwrap_t *topic = NULL;
+
+  uint8_t header_byte = 0;
+  header_byte |= (CONNECT << 4);
+
+
+  if (!jerry_value_is_undefined(jwill) && jerry_get_boolean_value(jwill)) {
+    connect_flags |= MQTT_FLAG_WILL;
+    if (!jerry_value_is_undefined(jqos)) {
+      uint8_t qos = 0;
+      qos = jerry_get_number_value(qos);
+      if (qos) {
+        connect_flags |= (qos == 1) ? MQTT_FLAG_WILLQOS_1 : MQTT_FLAG_WILLQOS_2;
+      }
+    }
+
+    if (!jerry_value_is_undefined(jretain) &&
+        jerry_get_boolean_value(jretain)) {
+      connect_flags |= MQTT_FLAG_WILLRETAIN;
+    }
+    message = iotjs_bufferwrap_from_jbuffer(jmessage);
+    topic = iotjs_bufferwrap_from_jbuffer(jtopic);
+  }
+
+  if (!jerry_value_is_undefined(jusername)) {
+    connect_flags |= MQTT_FLAG_USERNAME;
+    username = iotjs_bufferwrap_from_jbuffer(jusername);
+  }
+  if (!jerry_value_is_undefined(jpassword)) {
+    connect_flags |= MQTT_FLAG_PASSWORD;
+    password = iotjs_bufferwrap_from_jbuffer(jpassword);
+  }
+  if (!jerry_value_is_undefined(jkeepalive)) {
+    uint16_t len = jerry_get_number_value(jkeepalive);
+    keep_alive_msb = (uint8_t)(len >> 8);
+    keep_alive_lsb = (uint8_t)(len & 0x00FF);
+  }
+
+
+  iotjs_bufferwrap_t *client_id = iotjs_bufferwrap_from_jbuffer(jclient_id);
+
+  unsigned char variable_header_protocol[7];
+  variable_header_protocol[0] = 0;
+  variable_header_protocol[1] = 4;
+  variable_header_protocol[2] = 'M';
+  variable_header_protocol[3] = 'Q';
+  variable_header_protocol[4] = 'T';
+  variable_header_protocol[5] = 'T';
+  variable_header_protocol[6] = 4;
+
+  size_t variable_header_len = sizeof(variable_header_protocol) +
+                               sizeof(connect_flags) + sizeof(keep_alive_lsb) +
+                               sizeof(keep_alive_msb);
+
+  size_t payload_len = client_id->length + IOTJS_MQTT_LSB_MSB_SIZE;
+  if (connect_flags & MQTT_FLAG_USERNAME) {
+    payload_len += IOTJS_MQTT_LSB_MSB_SIZE + username->length;
+  }
+  if (connect_flags & MQTT_FLAG_PASSWORD) {
+    payload_len += IOTJS_MQTT_LSB_MSB_SIZE + password->length;
+  }
+  if (connect_flags & MQTT_FLAG_WILL) {
+    payload_len += IOTJS_MQTT_LSB_MSB_SIZE + topic->length;
+    payload_len += IOTJS_MQTT_LSB_MSB_SIZE + message->length;
+  }
+  uint32_t remaining_length = payload_len + variable_header_len;
+  size_t full_len = sizeof(header_byte) +
+                    get_remaining_length_size(remaining_length) +
+                    variable_header_len + payload_len;
+
+  jerry_value_t jbuff = iotjs_bufferwrap_create_buffer(full_len);
+  iotjs_bufferwrap_t *buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuff);
+
+  uint8_t *buff_ptr = (uint8_t *)buffer_wrap->buffer;
+
+  *buff_ptr++ = header_byte;
+  buff_ptr = iotjs_encode_remaining_length(buff_ptr, remaining_length);
+
+  memcpy(buff_ptr, variable_header_protocol, sizeof(variable_header_protocol));
+  buff_ptr += sizeof(variable_header_protocol);
+  *buff_ptr++ = connect_flags;
+  *buff_ptr++ = keep_alive_msb;
+  *buff_ptr++ = keep_alive_lsb;
+
+  buff_ptr = iotjs_mqtt_string_serialize(buff_ptr, client_id);
+
+  if (connect_flags & MQTT_FLAG_WILL) {
+    buff_ptr = iotjs_mqtt_string_serialize(buff_ptr, topic);
+    buff_ptr = iotjs_mqtt_string_serialize(buff_ptr, message);
+  }
+
+  if (connect_flags & MQTT_FLAG_USERNAME) {
+    buff_ptr = iotjs_mqtt_string_serialize(buff_ptr, username);
+  }
+  if (connect_flags & MQTT_FLAG_PASSWORD) {
+    buff_ptr = iotjs_mqtt_string_serialize(buff_ptr, password);
+  }
+
+  jerry_release_value(jretain);
+  jerry_release_value(jtopic);
+  jerry_release_value(jmessage);
+  jerry_release_value(jqos);
+  jerry_release_value(jwill);
+  jerry_release_value(jkeepalive);
+  jerry_release_value(jclient_id);
+  jerry_release_value(jusername);
+  jerry_release_value(jpassword);
+
+  return jbuff;
+}
+
+
+JS_FUNCTION(MqttPublish) {
+  DJS_CHECK_THIS();
+
+  DJS_CHECK_ARGS(1, object);
+
+  jerry_value_t joptions = JS_GET_ARG(0, object);
+
+  jerry_value_t jmessage =
+      iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_MESSAGE);
+  jerry_value_t jtopic =
+      iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_TOPIC);
+  jerry_value_t jretain =
+      iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_RETAIN);
+  jerry_value_t jqos =
+      iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_QOS);
+  jerry_value_t jpacket_id =
+      iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_PACKETID);
+
+  uint8_t qos = 0;
+  if (jerry_value_is_number(jqos)) {
+    qos = jerry_get_number_value(jqos);
+  }
+
+  bool dup = false;
+
+  uint8_t header_byte = 0;
+  header_byte |= (PUBLISH << 4);
+  header_byte |= (dup << 3);
+  header_byte |= (qos << 1);
+  header_byte |= (jerry_get_boolean_value(jretain));
+
+  iotjs_bufferwrap_t *message_payload = iotjs_bufferwrap_from_jbuffer(jmessage);
+  iotjs_bufferwrap_t *topic_payload = iotjs_bufferwrap_from_jbuffer(jtopic);
+
+  uint8_t packet_identifier_lsb = 0;
+  uint8_t packet_identifier_msb = 0;
+
+  if (qos > 0 && jerry_value_is_number(jpacket_id)) {
+    uint16_t packet_identifier = jerry_get_number_value(jpacket_id);
+    packet_identifier_msb = (uint8_t)(packet_identifier >> 8);
+    packet_identifier_lsb = (uint8_t)(packet_identifier & 0x00FF);
+  }
+
+  size_t payload_len = message_payload->length + IOTJS_MQTT_LSB_MSB_SIZE;
+  size_t variable_header_len = topic_payload->length + IOTJS_MQTT_LSB_MSB_SIZE +
+                               sizeof(packet_identifier_msb) +
+                               sizeof(packet_identifier_lsb);
+  uint32_t remaining_length = payload_len + variable_header_len;
+  size_t full_len = sizeof(header_byte) +
+                    get_remaining_length_size(remaining_length) +
+                    variable_header_len + payload_len;
+
+  jerry_value_t jbuff = iotjs_bufferwrap_create_buffer(full_len);
+  iotjs_bufferwrap_t *buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuff);
+
+  uint8_t *buff_ptr = (uint8_t *)buffer_wrap->buffer;
+
+  *buff_ptr++ = header_byte;
+  buff_ptr = iotjs_encode_remaining_length(buff_ptr, remaining_length);
+  buff_ptr = iotjs_mqtt_string_serialize(buff_ptr, topic_payload);
+  *buff_ptr++ = packet_identifier_msb;
+  *buff_ptr++ = packet_identifier_lsb;
+
+  // Don't need to put length before the payload, so we can't use the
+  // iotjs_mqtt_string_serialize. The broker and the other clients calculate
+  // the payload length from remaining length and the topic length.
+  memcpy(buff_ptr, message_payload->buffer, message_payload->length);
+
+  jerry_release_value(jmessage);
+  jerry_release_value(jtopic);
+  jerry_release_value(jretain);
+
+  return jbuff;
+}
+
+
+JS_FUNCTION(MqttHandle) {
+  DJS_CHECK_THIS();
+  DJS_CHECK_ARGS(2, object, object);
+
+  jerry_value_t jsref = JS_GET_ARG(0, object);
+  jerry_value_t jparam = JS_GET_ARG(1, object);
+
+  iotjs_bufferwrap_t *buffer_wrap = iotjs_bufferwrap_from_jbuffer(jparam);
+  char *buffer = buffer_wrap->buffer;
+
+  char first_byte = buffer[0];
+  char packet_type = (first_byte >> 4) & 0x0F;
+
+  size_t offset = 1;
+  uint32_t remaining_length = iotjs_decode_remaining_length(buffer, &offset);
+
+  switch (packet_type) {
+    case CONNACK: {
+      if (remaining_length != 2) {
+        return JS_CREATE_ERROR(COMMON, "MQTT: CONNACK packet is corrupted");
+      }
+
+      uint8_t return_code = (uint8_t)buffer[++offset];
+
+      if (return_code != 0) {
+        return mqtt_client_connack_error(return_code);
+      }
+
+      jerry_value_t fn =
+          iotjs_jval_get_property(jsref, IOTJS_MAGIC_STRING__ONCONNECT);
+      iotjs_jargs_t jargs = iotjs_jargs_create(1);
+      iotjs_jargs_append_jval(&jargs, jsref);
+      iotjs_make_callback(fn, jsref, &jargs);
+
+      iotjs_jargs_destroy(&jargs);
+      jerry_release_value(fn);
+      break;
+    }
+    case PUBLISH: {
+      MQTTHeader header = { 0 };
+      header.bits.type = PUBLISH;
+      header.bits.dup = first_byte & 0x08;
+      header.bits.qos = (first_byte & 0x06) >> 1;
+      header.bits.retain = first_byte & 0x01;
+
+      uint8_t topic_length_MSB = (uint8_t)buffer[offset];
+      offset += sizeof(topic_length_MSB);
+
+      uint8_t topic_length_LSB = (uint8_t)buffer[offset];
+      offset += sizeof(topic_length_LSB);
+
+      uint16_t topic_length =
+          iotjs_mqtt_calculate_length(topic_length_MSB, topic_length_LSB);
+
+      jerry_value_t jtopic = iotjs_bufferwrap_create_buffer(topic_length);
+      iotjs_bufferwrap_t *topic_wrap = iotjs_bufferwrap_from_jbuffer(jtopic);
+
+      memcpy(topic_wrap->buffer, buffer + offset, topic_length);
+      offset += topic_length;
+
+      // The Packet Identifier field is only present in PUBLISH packets
+      // where the QoS level is 1 or 2.
+      uint16_t packet_identifier = 0;
+      if (header.bits.qos > 0) {
+        uint8_t packet_identifier_MSB = 0;
+        uint8_t packet_identifier_LSB = 0;
+
+
+        memcpy(&packet_identifier_MSB, buffer + offset, sizeof(uint8_t));
+        offset += sizeof(packet_identifier_MSB);
+
+        memcpy(&packet_identifier_LSB, buffer + offset, sizeof(uint8_t));
+        offset += sizeof(packet_identifier_LSB);
+
+        packet_identifier = iotjs_mqtt_calculate_length(packet_identifier_MSB,
+                                                        packet_identifier_LSB);
+      }
+
+      size_t payload_length =
+          (size_t)remaining_length - topic_length - sizeof(topic_length);
+
+      if (header.bits.qos > 0) {
+        payload_length -= sizeof(packet_identifier);
+      }
+
+      jerry_value_t jmessage = iotjs_bufferwrap_create_buffer(payload_length);
+      iotjs_bufferwrap_t *msg_wrap = iotjs_bufferwrap_from_jbuffer(jmessage);
+
+      IOTJS_ASSERT(jerry_is_valid_utf8_string((const uint8_t *)msg_wrap->buffer,
+                                              msg_wrap->length));
+
+      IOTJS_ASSERT(
+          jerry_is_valid_utf8_string((const uint8_t *)topic_wrap->buffer,
+                                     topic_wrap->length));
+
+      memcpy(msg_wrap->buffer, buffer + offset, payload_length);
+      offset += payload_length;
+
+      iotjs_jargs_t args = iotjs_jargs_create(5);
+      iotjs_jargs_append_jval(&args, jsref);
+      iotjs_jargs_append_string_raw(&args, msg_wrap->buffer);
+      iotjs_jargs_append_string_raw(&args, topic_wrap->buffer);
+      iotjs_jargs_append_number(&args, header.bits.qos);
+      iotjs_jargs_append_number(&args, packet_identifier);
+
+      jerry_value_t fn =
+          iotjs_jval_get_property(jsref, IOTJS_MAGIC_STRING__ONMESSAGE);
+      iotjs_make_callback(fn, jsref, &args);
+      jerry_release_value(fn);
+
+      iotjs_jargs_destroy(&args);
+      jerry_release_value(jmessage);
+      jerry_release_value(jtopic);
+
+      break;
+    }
+    case PUBACK: {
+      if (remaining_length != 2) {
+        return JS_CREATE_ERROR(COMMON, "MQTT: PUBACK packet is corrupted");
+      }
+
+      iotjs_create_ack_callback(buffer, IOTJS_MAGIC_STRING__ONPUBACK, jsref);
+      break;
+    }
+    case PUBREC: {
+      if (remaining_length != 2) {
+        return JS_CREATE_ERROR(COMMON, "MQTT: RUBREC packet is corrupted");
+      }
+
+      iotjs_create_ack_callback(buffer, IOTJS_MAGIC_STRING__ONPUBREC, jsref);
+      break;
+    }
+    case PUBREL: {
+      if (remaining_length != 2) {
+        return JS_CREATE_ERROR(COMMON, "MQTT: PUBREL packet is corrupted");
+      }
+
+      char control_packet_reserved = first_byte & 0x0F;
+      if (control_packet_reserved != 2) {
+        return JS_CREATE_ERROR(COMMON, "MQTT: PUBREL packet is corrupted");
+      }
+
+      iotjs_create_ack_callback(buffer, IOTJS_MAGIC_STRING__ONPUBREL, jsref);
+      break;
+    }
+    case PUBCOMP: {
+      if (remaining_length != 2) {
+        return JS_CREATE_ERROR(COMMON, "MQTT: PUBCOMP packet is corrupted");
+      }
+
+      iotjs_create_ack_callback(buffer, IOTJS_MAGIC_STRING__ONPUBCOMP, jsref);
+      break;
+    }
+    case SUBACK: {
+      // We assume that only one topic was in the SUBSCRIBE packet.
+      if (remaining_length != 3) {
+        return JS_CREATE_ERROR(COMMON, "MQTT: SUBACK packet is corrupted");
+      }
+
+      uint8_t return_code = (uint8_t)buffer[4];
+      if (return_code == 128) {
+        return JS_CREATE_ERROR(COMMON, "MQTT: Subscription was unsuccessful");
+      }
+
+      // The callback takes the granted QoS as parameter.
+      iotjs_jargs_t args = iotjs_jargs_create(2);
+      iotjs_jargs_append_jval(&args, jsref);
+      iotjs_jargs_append_number(&args, return_code);
+
+      jerry_value_t sub_fn =
+          iotjs_jval_get_property(jsref, IOTJS_MAGIC_STRING__ONSUBACK);
+      iotjs_make_callback(sub_fn, jsref, &args);
+      jerry_release_value(sub_fn);
+      iotjs_jargs_destroy(&args);
+      break;
+    }
+    case UNSUBACK: {
+      if (remaining_length != 2) {
+        return JS_CREATE_ERROR(COMMON, "MQTT: UNSUBACK packet is corrupted");
+      }
+
+      iotjs_create_ack_callback(buffer, IOTJS_MAGIC_STRING__ONUNSUBACK, jsref);
+      break;
+    }
+    case PINGRESP: {
+      if (remaining_length != 0) {
+        return JS_CREATE_ERROR(COMMON, "MQTT: PingRESP packet is corrupted");
+      }
+      jerry_value_t fn =
+          iotjs_jval_get_property(jsref, IOTJS_MAGIC_STRING__ONPINGRESP);
+      iotjs_jargs_t jargs = iotjs_jargs_create(1);
+      iotjs_jargs_append_jval(&jargs, jsref);
+      iotjs_make_callback(fn, jsref, &jargs);
+      jerry_release_value(fn);
+      iotjs_jargs_destroy(&jargs);
+      break;
+    }
+    case DISCONNECT: {
+      iotjs_jargs_t jargs = iotjs_jargs_create(2);
+      iotjs_jargs_append_jval(&jargs, jsref);
+      jerry_value_t str_arg = jerry_create_string(
+          (jerry_char_t *)"The broker disconnected the client");
+      iotjs_jargs_append_jval(&jargs, str_arg);
+      jerry_value_t fn =
+          iotjs_jval_get_property(jsref, IOTJS_MAGIC_STRING__ONDISCONNECT);
+      iotjs_make_callback(fn, jsref, &jargs);
+      jerry_release_value(str_arg);
+      jerry_release_value(fn);
+      iotjs_jargs_destroy(&jargs);
+      break;
+    }
+
+    case CONNECT:
+    case SUBSCRIBE:
+    case UNSUBSCRIBE:
+    case PINGREQ:
+      return JS_CREATE_ERROR(
+          COMMON, "MQTT: Unallowed packet has arrived to the client");
+  }
+
+  return jerry_create_undefined();
+}
+
+
+JS_FUNCTION(MqttSubscribe) {
+  DJS_CHECK_THIS();
+  DJS_CHECK_ARGS(1, object);
+
+  jerry_value_t joptions = JS_GET_ARG(0, object);
+
+  jerry_value_t jtopic =
+      iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_TOPIC);
+  jerry_value_t jqos =
+      iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_QOS);
+
+  uint8_t qos = 0;
+  if (jerry_value_is_number(jqos)) {
+    qos = (uint8_t)jerry_get_number_value(jqos);
+  }
+
+  bool dup = false;
+  bool retain = false;
+
+  uint8_t header_byte = 0;
+  header_byte |= (SUBSCRIBE << 4);
+  header_byte |= (dup << 3);
+  header_byte |= (1 << 1); // always 1
+  header_byte |= retain;
+
+  iotjs_bufferwrap_t *topic_payload = iotjs_bufferwrap_from_jbuffer(jtopic);
+
+  uint8_t packet_identifier_lsb = 0;
+  uint8_t packet_identifier_msb = 0;
+
+  size_t payload_len =
+      sizeof(qos) + topic_payload->length + IOTJS_MQTT_LSB_MSB_SIZE;
+  size_t variable_header_len =
+      sizeof(packet_identifier_msb) + sizeof(packet_identifier_lsb);
+  uint32_t remaining_length = payload_len + variable_header_len;
+  size_t full_len = sizeof(header_byte) +
+                    get_remaining_length_size(remaining_length) +
+                    variable_header_len + payload_len;
+
+  jerry_value_t jbuff = iotjs_bufferwrap_create_buffer(full_len);
+  iotjs_bufferwrap_t *buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuff);
+
+  uint8_t *buff_ptr = (uint8_t *)buffer_wrap->buffer;
+
+  *buff_ptr++ = header_byte;
+
+  buff_ptr = iotjs_encode_remaining_length(buff_ptr, remaining_length);
+
+  *buff_ptr++ = packet_identifier_msb;
+  *buff_ptr++ = packet_identifier_lsb;
+
+  buff_ptr = iotjs_mqtt_string_serialize(buff_ptr, topic_payload);
+
+  buff_ptr[0] = qos;
+
+  jerry_release_value(jtopic);
+  jerry_release_value(jqos);
+
+  return jbuff;
+}
+
+
+JS_FUNCTION(MqttPing) {
+  DJS_CHECK_THIS();
+
+  uint8_t header_byte = 0;
+  header_byte |= (PINGREQ << 4);
+
+  uint8_t remaining_length = 0;
+  size_t full_len = sizeof(header_byte) + sizeof(remaining_length);
+
+  jerry_value_t jbuff = iotjs_bufferwrap_create_buffer(full_len);
+  iotjs_bufferwrap_t *buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuff);
+
+  uint8_t *buff_ptr = (uint8_t *)buffer_wrap->buffer;
+
+  buff_ptr[0] = header_byte;
+  buff_ptr[1] = remaining_length;
+
+  return jbuff;
+}
+
+
+JS_FUNCTION(MqttUnsubscribe) {
+  DJS_CHECK_THIS();
+  DJS_CHECK_ARGS(1, object);
+
+  jerry_value_t jtopic = JS_GET_ARG(0, object);
+
+  iotjs_bufferwrap_t *topic_payload = iotjs_bufferwrap_from_jbuffer(jtopic);
+
+  uint8_t header_byte = 0;
+  header_byte |= (UNSUBSCRIBE << 4);
+  // Reserved
+  header_byte |= (1 << 1);
+
+  uint8_t packet_identifier_msb = 0;
+  uint8_t packet_identifier_lsb = 0;
+
+  size_t payload_len = topic_payload->length + IOTJS_MQTT_LSB_MSB_SIZE;
+  size_t variable_header_len =
+      sizeof(packet_identifier_msb) + sizeof(packet_identifier_lsb);
+  uint32_t remaining_length = payload_len + variable_header_len;
+  size_t full_len = sizeof(header_byte) +
+                    get_remaining_length_size(remaining_length) +
+                    variable_header_len + payload_len;
+
+  jerry_value_t jbuff = iotjs_bufferwrap_create_buffer(full_len);
+  iotjs_bufferwrap_t *buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuff);
+
+  uint8_t *buff_ptr = (uint8_t *)buffer_wrap->buffer;
+
+  *buff_ptr++ = header_byte;
+
+  buff_ptr = iotjs_encode_remaining_length(buff_ptr, remaining_length);
+
+  *buff_ptr++ = packet_identifier_msb;
+  *buff_ptr++ = packet_identifier_lsb;
+
+  buff_ptr = iotjs_mqtt_string_serialize(buff_ptr, topic_payload);
+
+  return jbuff;
+}
+
+
+JS_FUNCTION(MqttDisconnect) {
+  DJS_CHECK_THIS();
+
+  uint8_t header_byte = 0;
+  uint8_t remaining_length = 0;
+  header_byte |= (DISCONNECT << 4);
+
+  size_t full_len = sizeof(header_byte) + sizeof(remaining_length);
+
+  jerry_value_t jbuff = iotjs_bufferwrap_create_buffer(full_len);
+  iotjs_bufferwrap_t *buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuff);
+
+  uint8_t *buff_ptr = (uint8_t *)buffer_wrap->buffer;
+
+  buff_ptr[0] = header_byte;
+  buff_ptr[1] = remaining_length;
+
+  return jbuff;
+}
+
+JS_FUNCTION(MqttSendAck) {
+  DJS_CHECK_THIS();
+  DJS_CHECK_ARGS(1, object);
+
+  jerry_value_t joptions = JS_GET_ARG(0, object);
+  jerry_value_t jack_type =
+      iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_ACKTYPE);
+  jerry_value_t jpacket_id =
+      iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_PACKETID);
+
+  uint16_t packet_id = 0;
+  if (!jerry_value_is_undefined(jpacket_id)) {
+    packet_id = (uint16_t)jerry_get_number_value(jpacket_id);
+  }
+
+  uint8_t ack_type = 0;
+  if (!jerry_value_is_undefined(jack_type)) {
+    ack_type = (uint8_t)jerry_get_number_value(jack_type);
+  }
+
+  uint8_t header_byte = 0;
+  uint8_t remaining_length = 2;
+
+  switch (ack_type) {
+    case PUBACK: {
+      header_byte |= (PUBACK << 4);
+      break;
+    }
+    case PUBREC: {
+      header_byte |= (PUBREC << 4);
+      break;
+    }
+    case PUBREL: {
+      header_byte |= (PUBREL << 4);
+      header_byte |= 2;
+      break;
+    }
+    case PUBCOMP: {
+      header_byte |= (PUBCOMP << 4);
+      break;
+    }
+  }
+
+  uint8_t packet_identifier_msb = (uint8_t)(packet_id >> 8);
+  uint8_t packet_identifier_lsb = (uint8_t)(packet_id & 0x00FF);
+
+  size_t full_len =
+      sizeof(header_byte) + sizeof(remaining_length) + sizeof(packet_id);
+
+  jerry_value_t jbuff = iotjs_bufferwrap_create_buffer(full_len);
+  iotjs_bufferwrap_t *buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuff);
+
+  uint8_t *buff_ptr = (uint8_t *)buffer_wrap->buffer;
+
+  buff_ptr[0] = header_byte;
+  buff_ptr[1] = remaining_length;
+  buff_ptr[2] = packet_identifier_msb;
+  buff_ptr[3] = packet_identifier_lsb;
+
+  jerry_release_value(jpacket_id);
+  jerry_release_value(jack_type);
+
+  return jbuff;
+}
+
+jerry_value_t InitMQTT() {
+  jerry_value_t jMQTT = jerry_create_object();
+  iotjs_jval_set_method(jMQTT, IOTJS_MAGIC_STRING_CONNECT, MqttConnect);
+  iotjs_jval_set_method(jMQTT, IOTJS_MAGIC_STRING_DISCONNECT, MqttDisconnect);
+  iotjs_jval_set_method(jMQTT, IOTJS_MAGIC_STRING_MQTTHANDLE, MqttHandle);
+  iotjs_jval_set_method(jMQTT, IOTJS_MAGIC_STRING_PING, MqttPing);
+  iotjs_jval_set_method(jMQTT, IOTJS_MAGIC_STRING_PUBLISH, MqttPublish);
+  iotjs_jval_set_method(jMQTT, IOTJS_MAGIC_STRING_SENDACK, MqttSendAck);
+  iotjs_jval_set_method(jMQTT, IOTJS_MAGIC_STRING_SUBSCRIBE, MqttSubscribe);
+  iotjs_jval_set_method(jMQTT, IOTJS_MAGIC_STRING_UNSUBSCRIBE, MqttUnsubscribe);
+
+  return jMQTT;
+}
diff --git a/src/modules/iotjs_module_mqtt.h b/src/modules/iotjs_module_mqtt.h
new file mode 100644 (file)
index 0000000..4a1f8e2
--- /dev/null
@@ -0,0 +1,130 @@
+/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors
+ *
+ * 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.
+ */
+
+#ifndef IOTJS_MODULE_MQTT_H
+#define IOTJS_MODULE_MQTT_H
+
+#include "iotjs_def.h"
+
+#define IOTJS_MODULE_MQTT_MAX_REMAINING_LENGTH_BYTES 4
+#define IOTJS_MQTT_LSB_MSB_SIZE 2
+
+/*
+ * The types of the control packet.
+ * These values determine the aim of the message.
+ */
+enum {
+  CONNECT = 0x1,
+  CONNACK = 0x2,
+  PUBLISH = 0x3,
+  PUBACK = 0x4,
+  PUBREC = 0x5,
+  PUBREL = 0x6,
+  PUBCOMP = 0x7,
+  SUBSCRIBE = 0x8,
+  SUBACK = 0x9,
+  UNSUBSCRIBE = 0xA,
+  UNSUBACK = 0xB,
+  PINGREQ = 0xC,
+  PINGRESP = 0xD,
+  DISCONNECT = 0xE
+} iotjs_mqtt_control_packet_type;
+
+/*
+ * The values of the Quality of Service.
+ */
+enum {
+  QoS0 = 0, // At most once delivery.
+  QoS1 = 1, // At least once delivery.
+  QoS2 = 2  // Exactly once delivery.
+} iotjs_mqtt_quality_of_service;
+
+enum {
+  UNACCEPTABLE_PROTOCOL = 1,
+  BAD_IDENTIFIER = 2,
+  SERVER_UNAVIABLE = 3,
+  BAD_CREDENTIALS = 4,
+  UNAUTHORISED = 5
+} iotjs_mqtt_connection_error;
+
+/*
+ * First byte of the message's fixed header.
+ * Contains:
+ * - MQTT Control Packet type,
+ * - Specific flags to each MQTT Control Packet.
+ */
+typedef struct {
+  uint8_t RETAIN : 1;    // PUBLISH Retain flag.
+  unsigned char QoS : 2; // PUBLISH Quality of Service.
+  uint8_t DUP : 1;       // Duplicate delivery of PUBLISH Control Packet.
+  unsigned char packet_type : 4;
+} iotjs_mqtt_control_packet_t;
+
+/*
+ * The fixed header of the MQTT message structure.
+ */
+typedef struct {
+  iotjs_mqtt_control_packet_t packet;
+  uint8_t remaining_length;
+} iotjs_mqtt_fixed_header_t;
+
+/*
+ * Type of the MQTT CONNECT message.
+ */
+
+typedef union {
+  unsigned char byte;
+
+  struct {
+    uint8_t retain : 1;
+    uint8_t qos : 2;
+    uint8_t dup : 1;
+    uint8_t type : 4;
+  } bits;
+} MQTTHeader;
+
+enum {
+  // Reserved bit, must be 0
+  MQTT_FLAG_RESERVED = 1 << 0,
+  // Clean session bit
+  MQTT_FLAG_CLEANSESSION = 1 << 1,
+  /**
+   * If the will flag is set to 1 Will QoS and Will Retain flags must be
+   * also set to 1, and be present in the payload. Otherwise, both must be set
+   * to 0.
+   */
+  MQTT_FLAG_WILL = 1 << 2,
+  /**
+   * QoS can only be set, if the Will flag is set to 1. Otherwise it's 0x00.
+   * QoS types are as follows:
+   * Type 0: Both QoS bits are set to 0 (0x00)
+   * Type 1: WILLQOS_1 is set to 1, WILLQOS_2 is set to 0 (0x01)
+   * Type 2: WILLQOS_2 is set to 1, WILLQOS_1 is set to 0 (0x02)
+   */
+  MQTT_FLAG_WILLQOS_1 = 1 << 3,
+  MQTT_FLAG_WILLQOS_2 = 1 << 4,
+  /**
+   * Will retain flag can only be set to 1 if Will flag is set to 1 as well.
+   * If retain is set to 1, the server must publish will message as a retained
+   * message.
+   */
+  MQTT_FLAG_WILLRETAIN = 1 << 5,
+  // Whether password is sent by the user
+  MQTT_FLAG_PASSWORD = 1 << 6,
+  // Whether username is sent
+  MQTT_FLAG_USERNAME = 1 << 7
+} iotjs_mqtt_connect_flag_t;
+
+#endif /* IOTJS_MODULE_MQTT_H */
index 66ab739..157fc39 100644 (file)
@@ -242,7 +242,8 @@ void SetNativeSources(jerry_value_t native_sources) {
 
 
 static void SetProcessEnv(jerry_value_t process) {
-  const char *homedir, *iotjspath, *iotjsenv, *extra_module_path;
+  const char *homedir, *iotjspath, *iotjsenv, *extra_module_path,
+      *working_dir_path;
 
   homedir = getenv(IOTJS_MAGIC_STRING_HOME_U);
   if (homedir == NULL) {
@@ -265,6 +266,7 @@ static void SetProcessEnv(jerry_value_t process) {
 #endif
 
   extra_module_path = getenv(IOTJS_MAGIC_STRING_IOTJS_EXTRA_MODULE_PATH_U);
+  working_dir_path = getenv(IOTJS_MAGIC_STRING_IOTJS_WORKING_DIR_PATH_U);
 
   jerry_value_t env = jerry_create_object();
   iotjs_jval_set_property_string_raw(env, IOTJS_MAGIC_STRING_HOME_U, homedir);
@@ -275,6 +277,9 @@ static void SetProcessEnv(jerry_value_t process) {
   iotjs_jval_set_property_string_raw(
       env, IOTJS_MAGIC_STRING_IOTJS_EXTRA_MODULE_PATH_U,
       extra_module_path ? extra_module_path : "");
+  iotjs_jval_set_property_string_raw(
+      env, IOTJS_MAGIC_STRING_IOTJS_WORKING_DIR_PATH_U,
+      working_dir_path ? working_dir_path : "");
 
   iotjs_jval_set_property_jval(process, IOTJS_MAGIC_STRING_ENV, env);
 
@@ -322,18 +327,33 @@ static void SetBuiltinModules(jerry_value_t builtin_modules) {
   }
 }
 
+static void SetProcessPrivate(jerry_value_t process, bool wait_source) {
+  jerry_value_t private = jerry_create_object();
+  iotjs_jval_set_property_jval(process, IOTJS_MAGIC_STRING_PRIVATE, private);
+
+  iotjs_jval_set_method(private, IOTJS_MAGIC_STRING_COMPILE, Compile);
+  iotjs_jval_set_method(private, IOTJS_MAGIC_STRING_COMPILEMODULE,
+                        CompileModule);
+  iotjs_jval_set_method(private, IOTJS_MAGIC_STRING_READSOURCE, ReadSource);
+
+  // debugger
+  iotjs_jval_set_method(private, IOTJS_MAGIC_STRING_DEBUGGERGETSOURCE,
+                        DebuggerGetSource);
+
+  jerry_value_t wait_source_val = jerry_create_boolean(wait_source);
+  iotjs_jval_set_property_jval(private, IOTJS_MAGIC_STRING_DEBUGGERWAITSOURCE,
+                               wait_source_val);
+
+  jerry_release_value(wait_source_val);
+  jerry_release_value(private);
+}
+
 
 jerry_value_t InitProcess() {
   jerry_value_t process = jerry_create_object();
 
-  iotjs_jval_set_method(process, IOTJS_MAGIC_STRING_COMPILE, Compile);
-  iotjs_jval_set_method(process, IOTJS_MAGIC_STRING_COMPILEMODULE,
-                        CompileModule);
-  iotjs_jval_set_method(process, IOTJS_MAGIC_STRING_READSOURCE, ReadSource);
   iotjs_jval_set_method(process, IOTJS_MAGIC_STRING_CWD, Cwd);
   iotjs_jval_set_method(process, IOTJS_MAGIC_STRING_CHDIR, Chdir);
-  iotjs_jval_set_method(process, IOTJS_MAGIC_STRING_DEBUGGERGETSOURCE,
-                        DebuggerGetSource);
   iotjs_jval_set_method(process, IOTJS_MAGIC_STRING_DOEXIT, DoExit);
   SetProcessEnv(process);
 
@@ -358,22 +378,17 @@ jerry_value_t InitProcess() {
 
   // Set iotjs
   SetProcessIotjs(process);
-  bool wait_source;
+  bool wait_source = false;
   if (iotjs_environment_config(iotjs_environment_get())->debugger != NULL) {
     wait_source = iotjs_environment_config(iotjs_environment_get())
                       ->debugger->wait_source;
-  } else {
-    wait_source = false;
   }
 
   if (!wait_source) {
     SetProcessArgv(process);
   }
 
-  jerry_value_t wait_source_val = jerry_create_boolean(wait_source);
-  iotjs_jval_set_property_jval(process, IOTJS_MAGIC_STRING_DEBUGGERWAITSOURCE,
-                               wait_source_val);
-  jerry_release_value(wait_source_val);
+  SetProcessPrivate(process, wait_source);
 
   return process;
 }
index d58b871..9d00793 100644 (file)
 #include "modules/iotjs_module_bridge.h"
 
 #include <app_common.h>
-#include <app_control.h>
-#include <bundle.h>
+#include <stdlib.h>
 
 typedef enum {
-  IOTJS_ERROR_NONE = 0,
-  IOTJS_ERROR_RESULT_FAILED,
+  IOTJS_ERROR_RESULT_FAILED = INT_MIN,
   IOTJS_ERROR_INVALID_PARAMETER,
+  IOTJS_ERROR_OUT_OF_MEMORY,
+  IOTJS_ERROR_NONE = 0,
 } iotjs_error_t;
 
-// application control
+// # tizen app-control
+#include <app_control.h>
 #include <app_control_internal.h>
+#include <bundle.h>
 #include <bundle_internal.h>
 
-iotjs_error_t send_launch_request(const char* json, void* hbridge) {
+static iotjs_error_t tizen_send_launch_request(const char* json,
+                                               void* hbridge) {
   DDDLOG("%s", __func__);
 
   bundle* b;
@@ -87,7 +90,7 @@ iotjs_error_t send_launch_request(const char* json, void* hbridge) {
 }
 
 
-void iotjs_service_app_control_cb(app_control_h app_control, void* user_data) {
+void iotjs_tizen_app_control_cb(app_control_h app_control, void* user_data) {
   DDDLOG("%s", __func__);
 
   iotjs_environment_t* env = iotjs_environment_get();
@@ -123,7 +126,7 @@ void iotjs_service_app_control_cb(app_control_h app_control, void* user_data) {
 
   iotjs_make_callback(fn, tizen, &jargv);
 
-  IOTJS_RELEASE(json);
+  free(json);
   bundle_free(b);
 
   jerry_release_value(fn);
@@ -131,16 +134,20 @@ void iotjs_service_app_control_cb(app_control_h app_control, void* user_data) {
 }
 
 
+// # tizen bridge
 void iotjs_tizen_func(const char* command, const char* message, void* handle) {
   DDDLOG("%s, cmd: %s, msg: %s", __func__, command, message);
 
   if (strncmp(command, "getResPath", strlen("getResPath")) == 0) {
     char* app_res_path = app_get_resource_path();
     iotjs_bridge_set_msg(handle, app_res_path);
+    if (app_res_path != NULL) {
+      free(app_res_path);
+    }
 
   } else if (strncmp(command, "launchAppControl", strlen("launchAppControl")) ==
              0) {
-    iotjs_error_t err = send_launch_request(message, handle);
+    iotjs_error_t err = tizen_send_launch_request(message, handle);
     if (err == IOTJS_ERROR_NONE) {
       iotjs_bridge_set_msg(handle, "OK");
     }
@@ -149,3 +156,107 @@ void iotjs_tizen_func(const char* command, const char* message, void* handle) {
     iotjs_bridge_set_err(handle, "Can't find command");
   }
 }
+
+
+// # tizen bridge-native
+typedef void (*user_callback_t)(int error, const char* data);
+
+typedef struct {
+  uv_async_t async;
+  char* module;
+  char* fn_name;
+  char* message;
+  user_callback_t cb;
+} iotjs_call_jfunc_t;
+
+
+static char* create_string_buffer(const char* src, size_t size) {
+  char* dest = IOTJS_CALLOC(size + 1, char);
+  strncpy(dest, src, size);
+  dest[size] = '\0'; // just for being sure
+  return dest;
+}
+
+
+static bool bridge_native_call(const char* module_name, const char* func_name,
+                               const char* message,
+                               iotjs_string_t* output_str) {
+  bool result = false;
+
+  jerry_value_t jmodule = iotjs_module_get(module_name);
+  jerry_value_t jfunc = iotjs_jval_get_property(jmodule, func_name);
+
+  if (jerry_value_is_function(jfunc) == false) {
+    return result;
+  }
+
+  iotjs_jargs_t jargv = iotjs_jargs_create(1);
+  iotjs_jargs_append_string_raw(&jargv, message);
+  jerry_value_t jres = iotjs_make_callback_with_result(jfunc, jmodule, &jargv);
+
+  if (jerry_value_is_string(jres)) {
+    IOTJS_ASSERT(output_str != NULL);
+    *output_str = iotjs_jval_as_string(jres);
+    result = true;
+  }
+
+  jerry_release_value(jfunc);
+  jerry_release_value(jres);
+  iotjs_jargs_destroy(&jargv);
+  return result;
+}
+
+
+static void bridge_native_async_handler(uv_async_t* handle) {
+  DDDLOG("%s\n", __func__);
+  iotjs_call_jfunc_t* data = (iotjs_call_jfunc_t*)handle->data;
+
+  bool result;
+  iotjs_string_t output;
+
+  result = bridge_native_call(IOTJS_MAGIC_STRING_TIZEN, data->fn_name,
+                              data->message, &output);
+
+  if (data->cb) {
+    data->cb((int)!result, iotjs_string_data(&output));
+  }
+
+  iotjs_string_destroy(&output);
+
+  // release
+  uv_close((uv_handle_t*)&data->async, NULL);
+  IOTJS_RELEASE(data->module);
+  IOTJS_RELEASE(data->fn_name);
+  IOTJS_RELEASE(data->message);
+  IOTJS_RELEASE(data);
+}
+
+
+int iotjs_tizen_bridge_native(const char* fn_name, unsigned fn_name_size,
+                              const char* message, unsigned message_size,
+                              user_callback_t cb) {
+  iotjs_environment_t* env = iotjs_environment_get();
+
+  if (env->state != kRunningMain && env->state != kRunningLoop) {
+    return IOTJS_ERROR_RESULT_FAILED;
+  }
+
+  iotjs_call_jfunc_t* handle = IOTJS_ALLOC(iotjs_call_jfunc_t);
+
+  if (handle == NULL) {
+    return IOTJS_ERROR_OUT_OF_MEMORY;
+  }
+
+  handle->async.data = (void*)handle;
+  handle->fn_name = create_string_buffer(fn_name, fn_name_size);
+  handle->message = create_string_buffer(message, message_size);
+  handle->module = create_string_buffer(IOTJS_MAGIC_STRING_TIZEN,
+                                        sizeof(IOTJS_MAGIC_STRING_TIZEN));
+  handle->cb = cb;
+
+  uv_loop_t* loop = iotjs_environment_loop(env);
+  uv_async_init(loop, &handle->async, bridge_native_async_handler);
+  uv_async_send(&handle->async);
+
+  return IOTJS_ERROR_NONE;
+}
index 56d5847..7024e48 100644 (file)
@@ -180,8 +180,11 @@ int iotjs_service_app_start(int argc, char** argv, char* js_path,
     return 1;
   }
 
+  // The JavaScript entry file is located in application res directory.
   snprintf(js_absolute_path, sizeof(js_absolute_path), "%s%s", app_res_path,
            js_path);
+  setenv(IOTJS_MAGIC_STRING_IOTJS_WORKING_DIR_PATH_U, app_res_path, 1);
+
   IOTJS_RELEASE(app_res_path);
 
   service_app_loop_method_s loop_method = {.init = loop_method_init_cb,
index eb56a88..7c69322 100644 (file)
@@ -16,6 +16,8 @@
 #ifndef IOTJS_TIZEN_SERVICE_APP_H
 #define IOTJS_TIZEN_SERVICE_APP_H
 
+#include <app_control.h>
+#include <string.h>
 
 #ifdef __cplusplus
 #define IOTJS_EXTERN_C extern "C"
 #define IOTJS_EXTERN_C extern
 #endif /* !__cplusplus */
 
+typedef void (*user_callback_t)(int error, const char* data);
+
 
 IOTJS_EXTERN_C int iotjs_service_app_start(int argc, char** argv, char* js_path,
                                            void* event_callbacks,
                                            void* user_data);
 
+IOTJS_EXTERN_C
+void iotjs_tizen_app_control_cb(app_control_h app_control, void* user_data);
+
+IOTJS_EXTERN_C
+int iotjs_tizen_bridge_native(const char* fn_name, unsigned fn_name_size,
+                              const char* message, unsigned message_size,
+                              user_callback_t cb);
+
+#define IOTJS_TIZEN_CALL_JFUNC(name, msg, cb)                              \
+  ({                                                                       \
+    if (name != NULL && (msg) != NULL)                                     \
+      iotjs_tizen_bridge_native(name, strlen(name), msg, strlen(msg), cb); \
+  })
+
 
 #endif /* IOTJS_TIZEN_SERVICE_APP_H */
diff --git a/test/run_pass/test_process_readsource.js b/test/run_pass/test_process_readsource.js
deleted file mode 100644 (file)
index a582d44..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/* Copyright 2017-present Samsung Electronics Co., Ltd. and other contributors
- *
- * 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.
- */
-
-var assert = require('assert');
-
-var json_file = process.cwd() + "/resources/process/package.json";
-
-// Load a JSON file.
-var str = process.readSource(json_file);
-var json = JSON.parse(str);
-
-assert.equal(json.version, "2.9.1");
-assert.equal(json.name, "npm");
-assert.equal(json.main, "./lib/npm.js");
-assert.equal(json.repository.type, "git");
index 23e8f49..dd0ee23 100644 (file)
@@ -86,7 +86,6 @@
     { "name": "test_process_experimental_off.js", "skip": ["experimental"], "reason": "needed if testing stablity is set with stable" },
     { "name": "test_process_experimental_on.js", "skip": ["stable"], "reason": "needed if testing stablity is set with experimental" },
     { "name": "test_process_next_tick.js" },
-    { "name": "test_process_readsource.js" },
     { "name": "test_process_uncaught_order.js" },
     { "name": "test_process_uncaught_simple.js" },
     { "name": "test_pwm_async.js", "skip": ["all"], "reason": "need to setup test environment" },
     { "name": "issue-1077.js" },
     { "name": "issue-1101.js", "skip": ["all"], "reason": "need to setup test environment" },
     { "name": "issue-1348.js" },
-    { "name": "issue-1351.js" },
     { "name": "issue-1485.js" },
     { "name": "issue-1507.js" },
     { "name": "issue-1557.js" }
index d5568bc..aa8c87b 100644 (file)
@@ -25,12 +25,19 @@ if (process.platform === 'linux') {
   pin.spi1 = '/dev/spidev0.0';
   pin.uart1 = '/dev/ttyS0';
 } else if (process.platform === 'tizen') {
-  pin.led = 20;
-  pin.switch = 13;
-  pin.pwm1 = 2;
+  if (process.iotjs.board === 'rpi3') {
+    pin.led = 20;
+    pin.switch = 13;
+    pin.spi1 = 0;
+    pin.uart1 = 0;
+  } else if (process.iotjs.board === 'artik530') {
+    pin.led = 128;
+    pin.switch = 27;
+    pin.pwm1 = 2;
+    pin.spi1 = 2;
+    pin.uart1 = 4;
+  }
   pin.i2c1 = 1;
-  pin.spi1 = 0;
-  pin.uart1 = 0;
 } else if (process.platform === 'nuttx') {
   var stm32_pin = require('stm32f4dis').pin;
   pin.led = stm32_pin.PA10;
index 91250e3..b30bf61 100755 (executable)
@@ -71,130 +71,126 @@ def init_options():
     argv = argv + sys.argv[1:]
 
     # Prepare argument parser.
-    parser = argparse.ArgumentParser()
+    parser = argparse.ArgumentParser(description='Building tool for IoT.js '
+        'JavaScript framework for embedded systems.')
 
-    parser.add_argument('--buildtype',
+    iotjs_group = parser.add_argument_group('Arguments of IoT.js',
+        'The following arguments are related to the IoT.js framework.')
+    iotjs_group.add_argument('--buildtype',
         choices=['debug', 'release'], default='debug',
-        help='Specify the build type: %(choices)s (default: %(default)s)')
-
-    parser.add_argument('--builddir', default=path.BUILD_ROOT,
+        help='Specify the build type (default: %(default)s).')
+    iotjs_group.add_argument('--builddir', default=path.BUILD_ROOT,
         help='Specify the build directory (default: %(default)s)')
-    parser.add_argument('--buildlib', action='store_true', default=False,
-        help='Build IoT.js library only (default: %(default)s)')
-
-    parser.add_argument('--clean', action='store_true', default=False,
-        help='Clean build directory before build (default: %(default)s)')
-
-    parser.add_argument('--config', default=path.BUILD_CONFIG_PATH,
-        help='Specify the config file (default: %(default)s)',
-        dest='config_path')
-
-    parser.add_argument('--profile',
-        help='Specify the module profile file for IoT.js')
-
-    parser.add_argument('--target-arch',
-        choices=['arm', 'x86', 'i686', 'x86_64', 'x64', 'mips', 'noarch'],
-        default=platform.arch(),
-        help='Specify the target architecture: '
-             '%(choices)s (default: %(default)s)')
-    parser.add_argument('--target-os',
-        choices=['linux', 'darwin', 'osx', 'nuttx', 'tizen', 'tizenrt',
-                 'openwrt'],
-        default=platform.os(),
-        help='Specify the target os: %(choices)s (default: %(default)s)')
-
-    parser.add_argument('--target-board',
-        choices=[None, 'artik10', 'stm32f4dis', 'rpi2', 'rpi3', 'artik05x'],
-        default=None, help='Specify the target board (if needed): '
-             '%(choices)s (default: %(default)s)')
-    parser.add_argument('--nuttx-home', default=None, dest='sysroot',
-        help='Specify the NuttX base directory (required for NuttX build)')
-
-    parser.add_argument('--sysroot', action='store',
-        help='The location of the development tree root directory (sysroot).'
-        'Must be compatible with used toolchain.')
-
-    parser.add_argument('--cmake-param',
+    iotjs_group.add_argument('--buildlib', action='store_true', default=False,
+        help='Build IoT.js static library only (default: %(default)s)')
+    iotjs_group.add_argument('--create-shared-lib',
+        action='store_true', default=False,
+        help='Create shared library (default: %(default)s)')
+    iotjs_group.add_argument('--cmake-param',
         action='append', default=[],
         help='Specify additional cmake parameters '
              '(can be used multiple times)')
-    parser.add_argument('--compile-flag',
+    iotjs_group.add_argument('--compile-flag',
         action='append', default=[],
         help='Specify additional compile flags (can be used multiple times)')
-    parser.add_argument('--link-flag',
-        action='append', default=[],
-        help='Specify additional linker flags (can be used multiple times)')
-
-    parser.add_argument('--external-include-dir',
+    iotjs_group.add_argument('--clean', action='store_true', default=False,
+        help='Clean build directory before build (default: %(default)s)')
+    iotjs_group.add_argument('--config', default=path.BUILD_CONFIG_PATH,
+        help='Specify the config file (default: %(default)s)',
+        dest='config_path')
+    iotjs_group.add_argument('-e', '--experimental',
+        action='store_true', default=False,
+        help='Enable to build experimental features')
+    iotjs_group.add_argument('--external-include-dir',
         action='append', default=[],
         help='Specify additional external include directory '
              '(can be used multiple times)')
-    parser.add_argument('--external-lib',
+    iotjs_group.add_argument('--external-lib',
         action='append', default=[],
         help='Specify additional external library '
              '(can be used multiple times)')
-
-    parser.add_argument('--external-modules',
+    iotjs_group.add_argument('--external-modules',
         action='store', default=set(), type=lambda x: set(x.split(',')),
         help='Specify the path of modules.json files which should be processed '
              '(format: path1,path2,...)')
+    iotjs_group.add_argument('--link-flag',
+        action='append', default=[],
+        help='Specify additional linker flags (can be used multiple times)')
+    iotjs_group.add_argument('--no-check-valgrind',
+        action='store_true', default=False,
+        help='Disable test execution with valgrind after build')
+    iotjs_group.add_argument('--no-init-submodule',
+        action='store_true', default=False,
+        help='Disable initialization of git submodules')
+    iotjs_group.add_argument('--no-parallel-build',
+        action='store_true', default=False,
+        help='Disable parallel build')
+    iotjs_group.add_argument('--no-snapshot',
+        action='store_true', default=False,
+        help='Disable snapshot generation for IoT.js')
+    iotjs_group.add_argument('--nuttx-home', default=None, dest='sysroot',
+        help='Specify the NuttX base directory (required for NuttX build)')
+    iotjs_group.add_argument('--profile',
+        help='Specify the module profile file for IoT.js')
+    iotjs_group.add_argument('--run-test',
+        nargs='?', default=False, const="quiet", choices=["full", "quiet"],
+        help='Execute tests after build, optional argument specifies '
+             'the level of output for the testrunner')
+    iotjs_group.add_argument('--sysroot', action='store',
+        help='The location of the development tree root directory (sysroot). '
+             'Must be compatible with used toolchain.')
+    iotjs_group.add_argument('--target-arch',
+        choices=['arm', 'x86', 'i686', 'x86_64', 'x64', 'mips', 'noarch'],
+        default=platform.arch(),
+        help='Specify the target architecture (default: %(default)s).')
+    iotjs_group.add_argument('--target-board',
+        choices=[None, 'artik10', 'stm32f4dis', 'rpi2', 'rpi3', 'artik05x'],
+        default=None, help='Specify the target board (default: %(default)s).')
+    iotjs_group.add_argument('--target-os',
+        choices=['linux', 'darwin', 'osx', 'nuttx', 'tizen', 'tizenrt',
+                 'openwrt'],
+        default=platform.os(),
+        help='Specify the target OS (default: %(default)s).')
+    iotjs_group.add_argument('--testsets',
+        help='Specify the additional testsets file for IoT.js')
 
-    parser.add_argument('--jerry-cmake-param',
+
+    jerry_group = parser.add_argument_group('Arguments of JerryScript',
+        'The following arguments are related to the JavaScript engine under '
+        'the framework. For example they can change the enabled features of '
+        'the ECMA-262 standard.')
+    jerry_group.add_argument('--jerry-cmake-param',
         action='append', default=[],
         help='Specify additional cmake parameters for JerryScript '
-        '(can be used multiple times')
-    parser.add_argument('--jerry-compile-flag',
+        '(can be used multiple times)')
+    jerry_group.add_argument('--jerry-compile-flag',
         action='append', default=[],
         help='Specify additional compile flags for JerryScript '
-             '(can be used multiple times')
-    parser.add_argument('--jerry-lto',
+             '(can be used multiple times)')
+    jerry_group.add_argument('--jerry-debugger',
         action='store_true', default=False,
-        help='Build JerryScript with LTO enabled')
-
-    parser.add_argument('--jerry-heap-section',
-        action='store', default=None,
-        help='Specify the name of the JerryScript heap section')
-    parser.add_argument('--jerry-heaplimit',
+        help='Enable JerryScript-debugger')
+    jerry_group.add_argument('--jerry-heaplimit',
         type=int, default=build_config['jerry-heaplimit'],
         help='Specify the size of the JerryScript max heap size '
              '(default: %(default)s)')
-
-    parser.add_argument('--jerry-memstat',
+    jerry_group.add_argument('--jerry-heap-section',
+        action='store', default=None,
+        help='Specify the name of the JerryScript heap section')
+    jerry_group.add_argument('--jerry-lto',
+        action='store_true', default=False,
+        help='Build JerryScript with LTO enabled')
+    jerry_group.add_argument('--jerry-memstat',
         action='store_true', default=False,
         help='Enable JerryScript heap statistics')
-
-    parser.add_argument('--jerry-profile',
+    jerry_group.add_argument('--jerry-profile',
         choices=['es5.1', 'es2015-subset'], default='es5.1',
-        help='Specify the profile for JerryScript: %(choices)s'
-             ' (default: %(default)s)')
-    parser.add_argument('--jerry-debugger',
-        action='store_true', default=False,
-        help='Enable JerryScript-debugger')
-    parser.add_argument('--no-init-submodule',
-        action='store_true', default=False,
-        help='Disable initialization of git submodules')
-    parser.add_argument('--no-check-valgrind',
-        action='store_true', default=False,
-        help='Disable test execution with valgrind after build')
-    parser.add_argument('--run-test',
-        nargs='?', default=False, const="quiet", choices=["full", "quiet"],
-        help='Execute tests after build, optional argument specifies '
-             'the level of output for the testrunner')
-    parser.add_argument('--no-parallel-build',
-        action='store_true', default=False,
-        help='Disable parallel build')
-    parser.add_argument('--no-snapshot',
-        action='store_true', default=False,
-        help='Disable snapshot generation for IoT.js')
-    parser.add_argument('--js-backtrace',
+        help='Specify the profile for JerryScript (default: %(default)s).')
+    jerry_group.add_argument('--js-backtrace',
         choices=['ON', 'OFF'], type=str.upper,
         help='Enable/disable backtrace information of JavaScript code '
-        '(%(choices)s; default: ON in debug and OFF in release build)')
-    parser.add_argument('-e', '--experimental',
-        action='store_true', default=False,
-        help='Enable to build experimental features')
-    parser.add_argument('--testsets',
-        help='Specify the additional testsets file for IoT.js')
+             '(default: ON in debug and OFF in release build)')
+
 
     options = parser.parse_args(argv)
     options.config = build_config
@@ -318,6 +314,7 @@ def build_iotjs(options):
         '-DENABLE_LTO=%s' % get_on_off(options.jerry_lto), # --jerry-lto
         '-DENABLE_SNAPSHOT=%s' % get_on_off(not options.no_snapshot),
         '-DBUILD_LIB_ONLY=%s' % get_on_off(options.buildlib), # --buildlib
+        '-DCREATE_SHARED_LIB=%s' % get_on_off(options.create_shared_lib),
         # --jerry-memstat
         '-DFEATURE_MEM_STATS=%s' % get_on_off(options.jerry_memstat),
         # --external-modules
diff --git a/tools/check_sonarqube.sh b/tools/check_sonarqube.sh
new file mode 100755 (executable)
index 0000000..977dff8
--- /dev/null
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+# Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors
+#
+# 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.
+
+if [[ -n "${TRAVIS_PULL_REQUEST_SLUG}" &&
+         "${TRAVIS_PULL_REQUEST_SLUG}" != "${TRAVIS_REPO_SLUG}" ]]; then
+  echo "Skip: The pull request from ${TRAVIS_PULL_REQUEST_SLUG} is an \
+  external one. It's not supported yet in Travis-CI";
+else
+  git fetch --unshallow;
+  build-wrapper-linux-x86-64 --out-dir bw-output ./tools/build.py;
+  sonar-scanner;
+fi