diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000000..65587bb4a2 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +/build/** +/deps/** +/src/js/ble* diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000000..a4a114ee98 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,95 @@ +/* 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 es6 = { + 'generator-star-spacing': [2, 'after'], + 'no-var': 2, + 'prefer-rest-params': 2, + 'prefer-spread': 2, + 'rest-spread-spacing': 2, + 'yield-star-spacing': [2, 'after'], +} + +var eslintRecommended = { + 'no-console': 0, + 'no-empty': 0, // TODO: remove this feature + 'no-constant-condition': [2, { 'checkLoops': false }] +} + +var style = { + 'no-multi-spaces': 2, + 'no-multi-str': 2, + 'array-bracket-spacing': [2, 'never'], + 'block-spacing': [2, 'never'], + 'brace-style': 2, + 'comma-dangle': [2, 'always-multiline'], + 'comma-spacing': 2, + 'comma-style': 2, + 'computed-property-spacing': 2, + 'eol-last': 2, + 'func-call-spacing': 2, + 'key-spacing': 2, + 'keyword-spacing': 2, + 'linebreak-style': 2, + 'no-multiple-empty-lines': [2, {max: 2}], + 'no-tabs': 2, + 'no-trailing-spaces': 2, + 'semi-spacing': 2, + 'space-before-blocks': 2, + 'space-before-function-paren': [2, { + anonymous: 'never', + named: 'never', + }], + 'spaced-comment': [2, 'always'], + 'switch-colon-spacing': 2, + 'quotes': [2, 'single'], +} + +var syntax = { + 'no-plusplus': 0, + 'guard-for-in': 2, + 'no-caller': 2, + 'no-extend-native': 2, + 'no-new-wrappers': 2, + 'new-cap': [2, { 'capIsNew': false, 'newIsCapExceptions': ['native'] }], + 'no-array-constructor': 2, + 'no-new-object': 2, + 'semi': 2, +} + +module.exports = { + 'extends': 'eslint:recommended', + 'env': { + 'node': true, + 'es6': false, + }, + 'globals': { + 'native': true, + }, + 'rules': Object.assign( + eslintRecommended, + style, + syntax, + { + // Optional rules + 'max-len': [2, { + code: 80, + tabWidth: 2, + ignoreUrls: true, + ignoreTemplateLiterals: true, + ignoreRegExpLiterals: true + }], + }), +} diff --git a/.gitignore b/.gitignore index 1ab732e063..2776a5357f 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,15 @@ /src/iotjs_js.h /src/iotjs_js.c /src/iotjs_string_ext.inl.h +/src/iotjs_module_inl.h /test/tmp/* +/test/dynamicmodule/build/* +/tools/module_generator/output +/test/module_generator/test_c/*.a +/test/module_generator/test_c/*.o +/test/module_generator/test_cpp/*.a +/test/module_generator/test_cpp/*.o +eslint.log # IDE related files nbproject @@ -26,6 +34,13 @@ vgcore.* cscope.* *.pyc +# Dependency directories +node_modules/ +iotjs_modules/ + +# Coverage directory used by tools like istanbul +coverage + # ctags and ID database tags ID diff --git a/.gitmodules b/.gitmodules index c0b8b94cf6..6eb67de953 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,16 @@ [submodule "deps/jerry"] - path = deps/jerry - url = https://github.com/jerryscript-project/jerryscript.git + path = deps/jerry + url = https://github.com/jerryscript-project/jerryscript.git + ignore = untracked [submodule "deps/http-parser"] - path = deps/http-parser - url = https://github.com/Samsung/http-parser.git + path = deps/http-parser + url = https://github.com/Samsung/http-parser.git + ignore = untracked [submodule "deps/libtuv"] - path = deps/libtuv - url = https://github.com/Samsung/libtuv.git + path = deps/libtuv + url = https://github.com/Samsung/libtuv.git + ignore = untracked +[submodule "deps/mbedtls"] + path = deps/mbedtls + url = https://github.com/ARMmbed/mbedtls.git + ignore = untracked diff --git a/.travis.yml b/.travis.yml index 0957b33cf6..e4238f5eb2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,63 +2,99 @@ language: c os: linux dist: trusty -sudo: required - -before_install: - - if [[ "$INSTALL_ARM_DEPS" == "yes" ]]; then tools/apt-get-install-arm.sh; fi - - if [[ "$INSTALL_NUTTX_DEPS" == "yes" ]]; then tools/apt-get-install-nuttx.sh; fi - - if [[ "$INSTALL_TIZEN_DEPS" == "yes" ]]; then . tools/apt-get-install-tizen.sh; fi - - if [[ "$INSTALL_TRAVIS_I686_DEPS" == "yes" ]]; then tools/apt-get-install-travis-i686.sh; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then tools/apt-get-install-deps.sh; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then tools/brew-install-deps.sh; fi - -install: - -script: "tools/precommit.py $OPTS" - -env: - global: - - secure: "lUGzoKK/Yn4/OmpqLQALrIgfY9mQWE51deUawPrCO87UQ2GknfQ4BvwY3UT5QY0XnztPBP1+vRQ2qxbiAU7VWicp280sXDnh0FeuZD14FcE9l0FczraL12reoLu+gY5HWFfbkZncmcBsZkxDEYxhkM14FJU8fxyqGQW2ypJNz+gUGP+8r40Re5J3WjcddCQNe5IG8U+M9B4YeDHhN2QspLdN5pkgn56XtdGa3+qbecO2NpjJG5ltM9j1tTuo/Dg22DxrIFVfeFSFKUj4nfMrgPo5LevRsC/lfaBSCsj751eqrxRcQRh2hkpiIJ7mEBs2LL1EH9O6Mbj+eRh8BvIYqTB85VPNFc43sLWk14apcSVBrxJE5j3kP9sAsOD9Y5JynnkeuxYyISrkywwoX2uxsmCzIfGbwsv5VLToQzrqWlGYrHOAmVXNi8561dLfsWwxxFUjdqkZr1Kgc8UfnBEcBUtSiKCHS86/YUUbBJGkEkjDUS0GiqhFY4bXLQCR7EX4qDX3m6p7Mnh4NVUolpnSmyeYE/MjmqQ+7PJsPLL3EcIYmJ7dtW3mZ3yE2NyaFD0Pym9+TiuCCXRtrNVK1M3Kya64KNv+HbhjT/fTCgXLSeyDmJOKVAqugRlDo3b1KGR1LI0AfegzSA6mEC4e9JLjYiSnHPMUahzgLt8oU0hNFRY=" - matrix: - - OPTS="--test=host-linux" - - OPTS="--test=rpi2" INSTALL_ARM_DEPS=yes - - OPTS="--test=nuttx" INSTALL_NUTTX_DEPS=yes - - OPTS="--test=artik10" INSTALL_TIZEN_DEPS=yes - - OPTS="--test=misc" + +services: + - docker + +script: tools/travis_script.py matrix: include: - - os: osx - env: OPTS="--test=host-darwin" - - os: linux - before_install: - - tools/apt-get-install-deps.sh - - echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca- + - name: "Linux/x86-64 Build & Correctness Tests" + env: + - OPTS="host-linux" + + - name: "Mock Linux Build & Correctness Tests" + env: + - OPTS="mock-linux" + + - name: "Linux/x86-64 Build with N-API support & Correctness Tests" + env: + - OPTS="n-api" + install: + - npm install + + - name: "Raspberry Pi 2 Build Test" + env: + - OPTS="rpi2" + + - name: "STM32f4 Discovery with Nuttx Build Test" + env: + - OPTS="stm32f4dis" + + - name: "Tizen Build Test" + env: + - OPTS="tizen" + + - name: "ECMAScript 2015 features Build & Correctness Tests" + env: + - OPTS="es2015" + + - name: "External modules Build & Correctness Tests" + env: + - OPTS="external-modules" + + - name: "Linux/x86-64 without snapshot Build & Correctness Tests" + env: + - OPTS="no-snapshot" + + - name: "Misc checks (e.g. style checker)" + env: + - OPTS="misc" + addons: + apt: + packages: [clang-format-3.9, npm, valgrind] + install: + - npm install eslint + + - name: "OSX/x86-64 Build & Correctness Tests" + env: + - OPTS="host-darwin" + os: osx + addons: + homebrew: + packages: [cmake] + + - name: "ASAN Tests" + env: + - OPTS="asan" + + - name: "UBSAN Tests" + env: + - OPTS="ubsan" + + - name: "Coverity Scan" + env: + - OPTS="coverity" + # Declaration of the encrypted COVERITY_SCAN_TOKEN, created via the + # "travis encrypt" command using the project repo's public key. + - secure: "qbQASyP3/OzpzAp8xRFL2uOAHhMbO0jVRJFg9i8UcPurHUXj1Erk0hOmS3gxkkv7g2BU1mwsMz2SLwKtAEzEwES5rEmAbJ8Jf/zWEPqjXA1taOfCKRyuGGxIdQD1AcU3dIUbYd+CJ9JwmfLcb5XIcoEQVfd0etl7bkJu43bqTptc0lnT6HAsl+QZ9y3tJH4qklTg9lJI6hp2aVtvT/liTJgqfZlXs0SsgDmZZ9C6B1ienhRFQZLezEVCRrjIbUfcHH5IWkXkIjfCdMXfYLqLhTZVHU7lxCcZhOIpMSVX0W85Ov2YTAaKyhTmHCETjjVFw0RK2t42lm7C5l7j0peF+PCG2Qw/w/KMfNKWf8CBcZX/IquOUu7/EFtWE/rc7qi4bKhLwOYtqTAroJjkX6YsPaQlsryAbtsIMlkFvW8oI7TxzJ9HE7co70/rgEj7Qka/7SLptVWyUxVWtJRQqBCE/piUzyAe/GYsmX4Qje+fY+b5spWWvFscxsBP3J5qA2zhV4nJQvJmnRNhz1wMmfh5tKO9Hifeof6JeISlGFRGqSX/RtVriRtI60FyEsHk6lZQqtW+INSVTHjoewC29kIdttbH1qjJ8L5+PmsiZRrm4ER38tnOrH1cGz1PdcTQJGoqVcB446f5Uc9G76q23xR7wkfkqb3P6zlF379C2rE41ps=" addons: coverity_scan: project: - name: "Samsung/iotjs" + name: "jerryscript-project/iotjs" description: "Platform for Internet of Things with JavaScript" - notification_email: duddlf.choi@samsung.com - build_command: "tools/precommit.py --test=coverity" + notification_email: haesik.jun@samsung.com + build_command: "tools/travis_script.py" branch_pattern: master - env: OPTS="--test=coverity" - - compiler: gcc-4.9 - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - gcc-4.9 - - gcc-4.9-multilib - env: OPTS="--test=host-linux --buildtype=debug --buildoptions=--target-arch=i686,--compile-flag=-fsanitize=address,--compile-flag=-fno-omit-frame-pointer,--compile-flag=-fno-common,--compile-flag=-O2,--jerry-cmake-param=-DJERRY_LIBC=OFF,--jerry-cmake-param=-DFEATURE_SYSTEM_ALLOCATOR=ON,--no-snapshot,--no-check-valgrind" INSTALL_TRAVIS_I686_DEPS=yes ASAN_OPTIONS=detect_stack_use_after_return=1:check_initialization_order=true:strict_init_order=true - - compiler: gcc-4.9 + + - name: "SonarQube" addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - gcc-4.9 - - gcc-4.9-multilib - env: OPTS="--test=host-linux --buildtype=debug --buildoptions=--target-arch=i686,--compile-flag=-fsanitize=undefined,--compile-flag=-fno-omit-frame-pointer,--compile-flag=-fno-common,--jerry-cmake-param=-DJERRY_LIBC=OFF,--jerry-cmake-param=-DFEATURE_SYSTEM_ALLOCATOR=ON,--no-snapshot,--no-check-valgrind" INSTALL_TRAVIS_I686_DEPS=yes UBSAN_OPTIONS=print_stacktrace=1 + sonarcloud: + organization: "pando-project" + script: ./tools/check_sonarqube.sh + cache: + directories: + - '$HOME/.sonar/cache' + fast_finish: true diff --git a/CMakeLists.txt b/CMakeLists.txt index e639a826b6..9cab35a7e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,24 +13,18 @@ # limitations under the License. cmake_minimum_required(VERSION 2.8) +include(CheckCCompilerFlag) project(IOTJS C) -set(IOTJS_VERSION_MAJOR 0) -set(IOTJS_VERSION_MINOR 1) +set(IOTJS_VERSION_MAJOR 1) +set(IOTJS_VERSION_MINOR 0) -# Do a few default checks -if(NOT DEFINED PLATFORM_DESCRIPTOR) - message(FATAL_ERROR "No PLATFORM_DESCRIPTOR specified (format: -)") -endif() - -string(REPLACE "-" ";" PLATFORM_ARGS ${PLATFORM_DESCRIPTOR}) if(NOT DEFINED TARGET_OS) - list(GET PLATFORM_ARGS 1 TARGET_OS) + string(TOLOWER ${CMAKE_SYSTEM_NAME} TARGET_OS) message( - "TARGET_OS not specified, using '${TARGET_OS}' from PLATFORM_DESCRIPTOR") + "TARGET_OS not specified, using '${TARGET_OS}' from CMAKE_SYSTEM_NAME") endif() -string(TOUPPER "${TARGET_OS}" TARGET_OS) if(NOT CMAKE_BUILD_TYPE) message("CMAKE_BUILD_TYPE was not set! Configuring for Debug build!") @@ -54,24 +48,177 @@ if(NOT DEFINED ENABLE_LTO) set(ENABLE_LTO OFF) endif() -set(ROOT_DIR ${CMAKE_SOURCE_DIR}) +macro(iotjs_add_flags VAR) + foreach(_flag ${ARGN}) + set(${VAR} "${${VAR}} ${_flag}") + endforeach() +endmacro() + +macro(iotjs_add_compile_flags) + iotjs_add_flags(CMAKE_C_FLAGS ${ARGV}) +endmacro() + +macro(iotjs_add_link_flags) + iotjs_add_flags(IOTJS_LINKER_FLAGS ${ARGV}) +endmacro() + +macro(build_lib_name LIB_VAR NAME) + set(${LIB_VAR} + ${CMAKE_STATIC_LIBRARY_PREFIX}${NAME}${CMAKE_STATIC_LIBRARY_SUFFIX}) +endmacro() + +if(CMAKE_C_COMPILER_ID MATCHES "MSVC") + set(USING_MSVC 1) + set(CONFIG_TYPE $<$:Debug>$<$:Release>) + # disable warning C4820: 'x' bytes padding added after construct 'membername' + iotjs_add_compile_flags(-wd4820) + # disable warning C4668: 'symbol' is not defined as preprocessor macro, + # replacing with '0' for 'directives' + # some windows headers reports these warnings + iotjs_add_compile_flags(-wd4668) + # disable warning C4100: unreferenced formal parameter + iotjs_add_compile_flags(-wd4100) +endif() + +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 AND NOT "${TARGET_OS}" STREQUAL "darwin") + iotjs_add_link_flags(-no-pie) + endif() +else() + + iotjs_add_compile_flags(-fPIE) + if("${TARGET_OS}" STREQUAL "darwin") + iotjs_add_link_flags(-Wl,-pie) + else() + iotjs_add_link_flags(-pie) + endif() +endif() + +if (CREATE_SHARED_LIB) + iotjs_add_compile_flags(-fPIC) +endif() + +if(EXPERIMENTAL) + iotjs_add_compile_flags(-DEXPERIMENTAL) +endif() + +# Add arch-dependant flags +if(NOT DEFINED TARGET_ARCH) + message(WARNING "Use generic flags since TARGET_ARCH is not defined") + set(TARGET_ARCH "noarch") +endif() +if("${TARGET_ARCH}" STREQUAL "arm") + iotjs_add_compile_flags(-D__arm__ -mthumb -fno-short-enums -mlittle-endian) +elseif("${TARGET_ARCH}" STREQUAL "i686") + iotjs_add_compile_flags(-D__i686__ -D__x86__) + if(NOT USING_MSVC) + iotjs_add_compile_flags(-march=i686 -m32) + endif() +elseif("${TARGET_ARCH}" STREQUAL "x86_64") + iotjs_add_compile_flags(-D__x86_64__) +elseif("${TARGET_ARCH}" STREQUAL "mips") + message("MIPS support is experimental!") + if(NOT EXPERIMENTAL) + message(FATAL_ERROR "Missing --experimental build option for MIPS!") + endif() -# Common compile flags -set(CFLAGS_COMMON - -Wall - -Wextra - -Werror - -Wno-unused-parameter - -Wsign-conversion - -std=gnu99 -) + if(ENABLE_SNAPSHOT) + message(FATAL_ERROR "Cross endian snapshots are not supported. " + "Please disable snapshot mode for mips!") + endif() +elseif("${TARGET_ARCH}" STREQUAL "noarch") +else() + message(WARNING "Unknown target arch: ${TARGET_ARCH}.") +endif() + +# Add board-dependant flags +if(NOT DEFINED TARGET_BOARD) + set(TARGET_BOARD "generic") +endif() +iotjs_add_compile_flags(-DTARGET_BOARD=${TARGET_BOARD}) +string(TOUPPER ${TARGET_BOARD} TARGET_BOARD_UPPER) +string(CONCAT TARGET_BOARD_SYMBOL "TARGET_BOARD_" ${TARGET_BOARD_UPPER}) +iotjs_add_compile_flags(-D${TARGET_BOARD_SYMBOL}=1) + +if("${TARGET_BOARD}" STREQUAL "artik05x") + iotjs_add_compile_flags(-mcpu=cortex-r4 -mfpu=vfp3) +elseif("${TARGET_BOARD}" STREQUAL "artik10") + iotjs_add_compile_flags(-mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=softfp) +elseif("${TARGET_BOARD}" STREQUAL "rpi2") + iotjs_add_compile_flags(-mcpu=cortex-a7 -mfpu=neon-vfpv4) +elseif("${TARGET_BOARD}" STREQUAL "rpi3") + if("${TARGET_OS}" STREQUAL "tizen") + iotjs_add_compile_flags(-mfpu=neon-vfpv4 -mfloat-abi=softfp) + endif() +elseif("${TARGET_BOARD}" STREQUAL "stm32f4dis") + iotjs_add_compile_flags(-mcpu=cortex-m4 -march=armv7e-m -mfpu=fpv4-sp-d16) + iotjs_add_compile_flags(-mfloat-abi=hard) +elseif("${TARGET_BOARD}" STREQUAL "stm32f7nucleo") + iotjs_add_compile_flags(-mcpu=cortex-m7) + iotjs_add_compile_flags(-mfloat-abi=hard) +endif() + +# Add os-dependant flags +if("${TARGET_OS}" STREQUAL "darwin") + iotjs_add_compile_flags(-D__DARWIN__ -fno-builtin) +elseif("${TARGET_OS}" STREQUAL "linux") + iotjs_add_compile_flags(-D__LINUX__ -fno-builtin) + iotjs_add_link_flags(-pthread -rdynamic) + iotjs_add_flags(EXTERNAL_LIBS m rt) +elseif("${TARGET_OS}" STREQUAL "nuttx") + iotjs_add_compile_flags(-D__NUTTX__ -Os -fno-strict-aliasing) + iotjs_add_compile_flags(-fno-strength-reduce -fomit-frame-pointer) +elseif("${TARGET_OS}" STREQUAL "tizen") + iotjs_add_compile_flags(-D__TIZEN__ -fno-builtin) + iotjs_add_link_flags(-pthread -rdynamic) + iotjs_add_flags(EXTERNAL_LIBS m rt) +elseif("${TARGET_OS}" STREQUAL "tizenrt") + iotjs_add_compile_flags(-D__TIZENRT__ -Os -fno-strict-aliasing) + iotjs_add_compile_flags(-fno-strength-reduce -fomit-frame-pointer) +elseif("${TARGET_OS}" STREQUAL "windows") + message("Windows support is experimental!") + if(NOT EXPERIMENTAL) + message(FATAL_ERROR "Missing --experimental build option for Windows!") + endif() +elseif("${TARGET_OS}" STREQUAL "openwrt") + message("OpenWrt support is experimental!") + if(NOT EXPERIMENTAL) + message(FATAL_ERROR "Missing --experimental build option for OpenWrt!") + endif() + + iotjs_add_compile_flags(-D__OPENWRT__ -D_GNU_SOURCE) + iotjs_add_link_flags(-pthread) +else() + message(WARNING "Unknown target os: ${TARGET_OS}.") +endif() + +# Add external options +if(DEFINED EXTERNAL_COMPILE_FLAGS) + iotjs_add_compile_flags(${EXTERNAL_COMPILE_FLAGS}) +endif() + +if(DEFINED EXTERNAL_LINKER_FLAGS) + iotjs_add_link_flags(${EXTERNAL_LINKER_FLAGS}) +endif() + +string(TOUPPER "${TARGET_OS}" TARGET_OS) + +set(ROOT_DIR ${CMAKE_SOURCE_DIR}) +set(ARCHIVE_DIR ${CMAKE_BINARY_DIR}/lib) include(ExternalProject) +if(NOT ${EXTERNAL_LIBC_INTERFACE} STREQUAL "") + iotjs_add_compile_flags(-isystem ${EXTERNAL_LIBC_INTERFACE}) +endif() + # Include external projects include(cmake/jerry.cmake) include(cmake/http-parser.cmake) include(cmake/libtuv.cmake) include(cmake/iotjs.cmake) - diff --git a/README.md b/README.md index 7f53af5182..c5cd942e53 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,31 @@ # IoT.js: Platform for Internet of Things with JavaScript -[![Join the chat at https://gitter.im/Samsung/iotjs](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Samsung/iotjs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![License](https://img.shields.io/badge/licence-Apache%202.0-brightgreen.svg?style=flat)](LICENSE) -[![Build Status](https://travis-ci.org/Samsung/iotjs.svg?branch=master)](https://travis-ci.org/Samsung/iotjs) -[![Coverity Scan Build Status](https://img.shields.io/coverity/scan/12140.svg)](https://scan.coverity.com/projects/samsung-iotjs) +[![Build Status](https://travis-ci.org/jerryscript-project/iotjs.svg?branch=master)](https://travis-ci.org/jerryscript-project/iotjs) +[![Coverity Scan Build Status](https://scan.coverity.com/projects/12140/badge.svg)](https://scan.coverity.com/projects/samsung-iotjs) +[![SonarCloud Status](https://sonarcloud.io/api/project_badges/measure?project=pando-project_iotjs&metric=alert_status)](https://sonarcloud.io/dashboard?id=pando-project_iotjs) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2FSamsung%2Fiotjs.svg?type=shield)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2FSamsung%2Fiotjs?ref=badge_shield) +[![IRC Channel](https://img.shields.io/badge/chat-on%20freenode-brightgreen.svg)](https://kiwiirc.com/client/irc.freenode.net/#iotjs) -You can find project details on our [project page](http://samsung.github.io/iotjs/) and [wiki](https://github.com/Samsung/iotjs/wiki). +You can find project details on our [project page](http://jerryscript-project.github.io/iotjs/) and [wiki](https://github.com/jerryscript-project/iotjs/wiki). -IRC channel: #iotjs on [freenode](https://freenode.net) +Memory usage and Binary footprint are measured at [here](https://jerryscript-project.github.io/iotjs-test-results) with real target daily. + +The following table shows the latest results on the devices: + +| Raspberry Pi 3 | [![Remote Testrunner](https://firebasestorage.googleapis.com/v0/b/jsremote-testrunner.appspot.com/o/status%2Fiotjs%2Frpi3.svg?alt=media&token=1)](https://jerryscript-project.github.io/iotjs-test-results/?view=rpi3) | +| :---: | :---: | +| **Raspberry Pi 2** | [![Remote Testrunner](https://firebasestorage.googleapis.com/v0/b/jsremote-testrunner.appspot.com/o/status%2Fiotjs%2Frpi2.svg?alt=media&token=1)](https://jerryscript-project.github.io/iotjs-test-results/?view=rpi2) | +| **STM32F4-Discovery** | [![Remote Testrunner](https://firebasestorage.googleapis.com/v0/b/jsremote-testrunner.appspot.com/o/status%2Fiotjs%2Fstm32f4dis.svg?alt=media&token=1)](https://jerryscript-project.github.io/iotjs-test-results/?view=stm32f4dis) | + + +IRC channel: #iotjs on [freenode](https://freenode.net) Mailing list: iotjs-dev@groups.io, you can subscribe [here](https://groups.io/g/iotjs-dev) and access the mailing list archive [here](https://groups.io/g/iotjs-dev/topics). ## Quick Start ### Getting the sources ```bash -git clone https://github.com/Samsung/iotjs.git +git clone https://github.com/jerryscript-project/iotjs.git cd iotjs ``` @@ -27,14 +38,20 @@ tools/build.py ### How to Test ```bash -build/x86_64-linux/debug/bin/iotjs tools/check_test.js +tools/testrunner.py build/x86_64-linux/debug/bin/iotjs +``` + +### Trying out with a REPL + +```bash +build/x86_64-linux/debug/bin/iotjs tools/repl.js ``` -For Additional information see [Getting Started](docs/help/Getting-Started.md). +For Additional information see [Getting Started](docs/Getting-Started.md). ## Documentation -- [Getting Started](docs/help/Getting-Started.md) +- [Getting Started](docs/Getting-Started.md) - [API Reference](docs/api/IoT.js-API-reference.md) ## License diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000000..4b081ad795 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,43 @@ +version: "{build}" +branches: + except: + - coverity_scan + - gh_pages +skip_tags: true +image: + - Visual Studio 2017 +configuration: + - Debug + - Release +platform: + - Win32 + - x64 +init: + - cmd: | + if "%PLATFORM%"=="Win32" set SYS_ARCH=i686 + if "%PLATFORM%"=="x64" set SYS_ARCH=x86_64 + cmake -version + +install: + - ps: | + Install-Product node 10.15.3 + +artifacts: + - path: build\%SYS_ARCH%-windows\$(configuration)\bin\$(configuration)\ + name: IoTjsbinary + +before_build: + - cmd: | + tools\build.py --experimental --buildtype=%CONFIGURATION% --target-arch=%SYS_ARCH% --jerry-profile=es2015-subset --n-api + +build: + project: build\%SYS_ARCH%-windows\%CONFIGURATION%\IOTJS.sln + parallel: true + verbosity: minimal + +before_test: + - cmd: npm install + +test_script: + - cmd: | + tools\testrunner.py build\%SYS_ARCH%-windows\%CONFIGURATION%\bin\%CONFIGURATION%\iotjs.exe diff --git a/build.config b/build.config index 342c82e01e..e570eeaa56 100644 --- a/build.config +++ b/build.config @@ -1,116 +1,27 @@ { - "build_option" : { - "buildtype": "debug", - "buildlib": false, - "builddir": "", - "clean": false, - "config": "", - "target-arch": "", - "target-os": "", - "target-board":"", - "cmake-param": [], - "compile-flag": [], - "link-flag": [], - "external-include-dir": [], - "external-static-lib": [], - "external-shared-lib": [], - "jerry-cmake-param": [], - "jerry-compile-flag": [], - "jerry-link-flag": [], - "jerry-lto": false, - "jerry-heaplimit": 256, - "jerry-memstat": false, - "no-init-submodule": false, - "no-check-tidy": false, - "no-check-test": false, - "no-parallel-build": false, - "sysroot": "", - "no-snapshot": false - }, - "compile_flags": { - "os": { - "linux": ["-D__LINUX__", - "-fno-builtin"], - "darwin": ["-D__DARWIN__", - "-fno-builtin"], - "nuttx": ["-D__NUTTX__", - "-Os", - "-fno-strict-aliasing", - "-fno-strength-reduce", - "-fomit-frame-pointer"], - "tizen": ["-D__LINUX__", - "-fno-builtin"], - "tizenrt": ["-D__TIZENRT__", - "-Os", - "-fno-strict-aliasing", - "-fno-strength-reduce", - "-fomit-frame-pointer"] - }, - "arch": { - "i686": ["-D__i686__", - "-D__x86__", - "-D__I686__", - "-D__X86__", - "-march=i686", - "-m32"], - "x86_64": ["-D__x86_64__", - "-D__X86_64__"], - "arm": ["-D__ARM__", - "-D__arm__", - "-mthumb", - "-fno-short-enums", - "-mlittle-endian"] - }, - "board": { - "stm32f4dis": ["-mcpu=cortex-m4", - "-march=armv7e-m", - "-mfpu=fpv4-sp-d16", - "-mfloat-abi=hard", - "-DTARGET_BOARD=STM32F4DIS"], - "rpi2": ["-mcpu=cortex-a7", - "-mfpu=neon-vfpv4", - "-DTARGET_BOARD=RP2"], - "artik05x": ["-mcpu=cortex-r4", - "-mfpu=vfp3", - "-DTARGET_BOARD=artik05x"], - "artik10": ["-mcpu=cortex-a7", - "-mfpu=neon-vfpv4", - "-mfloat-abi=softfp", - "-DTARGET_BOARD=artik10"] - }, - "buildtype": { - "release": [], - "debug": ["-DDEBUG", - "-DENABLE_DEBUG_LOG"] - } - }, - "link_flags": { - "os": { - "linux": ["-pthread"], - "darwin": [], - "nuttx": [], - "tizen": ["-pthread"], - "tizenrt": [] - } - }, - "shared_libs": { - "os": { - "linux": ["m", "rt"], - "darwin": [], - "nuttx": [], - "tizen": ["m", "rt"], - "tizenrt": [] - } - }, - "module": { - "always": ["buffer", "console", "events", "fs", "module", "timers"], - "include": ["assert", "dns", "http", "net", "stream", "testdriver"], - "exclude": { - "all": [], - "linux": ["adc", "ble", "dgram", "gpio", "i2c", "pwm", "spi", "uart"], - "nuttx": ["adc", "dgram", "gpio", "i2c", "pwm", "stm32f4dis", "uart"], - "darwin": [], - "tizenrt": ["gpio", "pwm"] - } - } + "builddir": "", + "buildlib": false, + "buildtype": "debug", + "clean": false, + "config": "", + "cmake-param": [], + "compile-flag": [], + "external-include-dir": [], + "external-lib": [], + "jerry-cmake-param": [], + "jerry-compile-flag": [], + "jerry-heaplimit": 256, + "jerry-link-flag": [], + "jerry-lto": false, + "jerry-memstat": false, + "link-flag": [], + "no-check-tidy": false, + "no-init-submodule": false, + "no-parallel-build": false, + "no-snapshot": false, + "run-test": false, + "sysroot": "", + "target-arch": "", + "target-os": "", + "target-board": "" } diff --git a/cmake/JSONParser.cmake b/cmake/JSONParser.cmake new file mode 100644 index 0000000000..747cd630c5 --- /dev/null +++ b/cmake/JSONParser.cmake @@ -0,0 +1,324 @@ +# 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. +# +# The MIT License (MIT) +# +# Copyright (c) 2015 Stefan Bellus +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +cmake_minimum_required(VERSION 2.8) + +if (DEFINED JSonParserGuard) + return() +endif() + +set(JSonParserGuard yes) + +macro(sbeParseJson prefix jsonString) + cmake_policy(PUSH) + + set(json_string "${${jsonString}}") + string(LENGTH "${json_string}" json_jsonLen) + set(json_index 0) + set(json_AllVariables ${prefix}) + set(json_ArrayNestingLevel 0) + set(json_MaxArrayNestingLevel 0) + + _sbeParse(${prefix}) + + unset(json_index) + unset(json_AllVariables) + unset(json_jsonLen) + unset(json_string) + unset(json_value) + unset(json_inValue) + unset(json_name) + unset(json_inName) + unset(json_newPrefix) + unset(json_reservedWord) + unset(json_arrayIndex) + unset(json_char) + unset(json_end) + unset(json_ArrayNestingLevel) + foreach(json_nestingLevel RANGE ${json_MaxArrayNestingLevel}) + unset(json_${json_nestingLevel}_arrayIndex) + endforeach() + unset(json_nestingLevel) + unset(json_MaxArrayNestingLevel) + + cmake_policy(POP) +endmacro() + +macro(sbeClearJson prefix) + foreach(json_var ${${prefix}}) + unset(${json_var}) + endforeach() + + unset(${prefix}) + unset(json_var) +endmacro() + +macro(sbePrintJson prefix) + foreach(json_var ${${prefix}}) + message("${json_var} = ${${json_var}}") + endforeach() +endmacro() + +macro(_sbeParse prefix) + + while(${json_index} LESS ${json_jsonLen}) + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + + if("\"" STREQUAL "${json_char}") + _sbeParseNameValue(${prefix}) + elseif("{" STREQUAL "${json_char}") + _sbeMoveToNextNonEmptyCharacter() + _sbeParseObject(${prefix}) + elseif("[" STREQUAL "${json_char}") + _sbeMoveToNextNonEmptyCharacter() + _sbeParseArray(${prefix}) + endif() + + if(${json_index} LESS ${json_jsonLen}) + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + else() + break() + endif() + + if ("}" STREQUAL "${json_char}" OR "]" STREQUAL "${json_char}") + break() + endif() + + _sbeMoveToNextNonEmptyCharacter() + endwhile() +endmacro() + +macro(_sbeParseNameValue prefix) + set(json_name "") + set(json_inName no) + + while(${json_index} LESS ${json_jsonLen}) + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + + # check if name ends + if("\"" STREQUAL ${json_char} AND json_inName) + set(json_inName no) + _sbeMoveToNextNonEmptyCharacter() + if(NOT ${json_index} LESS ${json_jsonLen}) + break() + endif() + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + set(json_newPrefix ${prefix}.${json_name}) + set(json_name "") + + if(":" STREQUAL "${json_char}") + _sbeMoveToNextNonEmptyCharacter() + if(NOT ${json_index} LESS ${json_jsonLen}) + break() + endif() + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + + if("\"" STREQUAL "${json_char}") + _sbeParseValue(${json_newPrefix}) + break() + elseif("{" STREQUAL "${json_char}") + _sbeMoveToNextNonEmptyCharacter() + _sbeParseObject(${json_newPrefix}) + break() + elseif("[" STREQUAL "${json_char}") + _sbeMoveToNextNonEmptyCharacter() + _sbeParseArray(${json_newPrefix}) + break() + else() + # reserved word starts + _sbeParseReservedWord(${json_newPrefix}) + break() + endif() + else() + # name without value + list(APPEND ${json_AllVariables} ${json_newPrefix}) + set(${json_newPrefix} "") + break() + endif() + endif() + + if(json_inName) + # remove escapes + if("\\" STREQUAL ${json_char}) + math(EXPR json_index "${json_index} + 1") + if(NOT ${json_index} LESS ${json_jsonLen}) + break() + endif() + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + endif() + + set(json_name "${json_name}${json_char}") + endif() + + # check if name starts + if("\"" STREQUAL ${json_char} AND NOT json_inName) + set(json_inName yes) + endif() + + _sbeMoveToNextNonEmptyCharacter() + endwhile() +endmacro() + +macro(_sbeParseReservedWord prefix) + set(json_reservedWord "") + set(json_end no) + while(${json_index} LESS ${json_jsonLen} AND NOT json_end) + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + + if("," STREQUAL "${json_char}" + OR "}" STREQUAL "${json_char}" + OR "]" STREQUAL "${json_char}") + set(json_end yes) + else() + set(json_reservedWord "${json_reservedWord}${json_char}") + math(EXPR json_index "${json_index} + 1") + endif() + endwhile() + + list(APPEND ${json_AllVariables} ${prefix}) + string(STRIP "${json_reservedWord}" json_reservedWord) + set(${prefix} ${json_reservedWord}) +endmacro() + +macro(_sbeParseValue prefix) + set(json_value "") + set(json_inValue no) + + while(${json_index} LESS ${json_jsonLen}) + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + + # check if json_value ends, it is ended by " + if("\"" STREQUAL ${json_char} AND json_inValue) + set(json_inValue no) + + set(${prefix} ${json_value}) + list(APPEND ${json_AllVariables} ${prefix}) + _sbeMoveToNextNonEmptyCharacter() + break() + endif() + + if(json_inValue) + # if " is escaped consume + if("\\" STREQUAL ${json_char}) + math(EXPR json_index "${json_index} + 1") + if(NOT ${json_index} LESS ${json_jsonLen}) + break() + endif() + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + if(NOT "\"" STREQUAL "${json_char}") + # if it is not " then copy also escape character + set(json_char "\\${json_char}") + endif() + endif() + + set(json_value "${json_value}${json_char}") + endif() + + # check if value starts + if("\"" STREQUAL ${json_char} AND NOT json_inValue) + set(json_inValue yes) + endif() + + math(EXPR json_index "${json_index} + 1") + endwhile() +endmacro() + +macro(_sbeParseObject prefix) + _sbeParse(${prefix}) + _sbeMoveToNextNonEmptyCharacter() +endmacro() + +macro(_sbeParseArray prefix) + math(EXPR json_ArrayNestingLevel "${json_ArrayNestingLevel} + 1") + set(json_${json_ArrayNestingLevel}_arrayIndex 0) + + set(${prefix} "") + list(APPEND ${json_AllVariables} ${prefix}) + + while(${json_index} LESS ${json_jsonLen}) + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + + if("\"" STREQUAL "${json_char}") + # simple value + list(APPEND ${prefix} ${json_${json_ArrayNestingLevel}_arrayIndex}) + _sbeParseValue(${prefix}_${json_${json_ArrayNestingLevel}_arrayIndex}) + elseif("{" STREQUAL "${json_char}") + # object + _sbeMoveToNextNonEmptyCharacter() + list(APPEND ${prefix} ${json_${json_ArrayNestingLevel}_arrayIndex}) + _sbeParseObject(${prefix}_${json_${json_ArrayNestingLevel}_arrayIndex}) + else() + list(APPEND ${prefix} ${json_${json_ArrayNestingLevel}_arrayIndex}) + _sbeParseReservedWord( + ${prefix}_${json_${json_ArrayNestingLevel}_arrayIndex}) + endif() + + if(NOT ${json_index} LESS ${json_jsonLen}) + break() + endif() + + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + + if("]" STREQUAL "${json_char}") + _sbeMoveToNextNonEmptyCharacter() + break() + elseif("," STREQUAL "${json_char}") + math(EXPR json_${json_ArrayNestingLevel}_arrayIndex + "${json_${json_ArrayNestingLevel}_arrayIndex} + 1") + endif() + + _sbeMoveToNextNonEmptyCharacter() + endwhile() + + if(${json_MaxArrayNestingLevel} LESS ${json_ArrayNestingLevel}) + set(json_MaxArrayNestingLevel ${json_ArrayNestingLevel}) + endif() + math(EXPR json_ArrayNestingLevel "${json_ArrayNestingLevel} - 1") +endmacro() + +macro(_sbeMoveToNextNonEmptyCharacter) + math(EXPR json_index "${json_index} + 1") + if(${json_index} LESS ${json_jsonLen}) + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + while(${json_char} MATCHES "[ \t\n\r]" + AND ${json_index} LESS ${json_jsonLen}) + math(EXPR json_index "${json_index} + 1") + if(${json_index} LESS ${json_jsonLen}) + string(SUBSTRING "${json_string}" ${json_index} 1 json_char) + endif() + endwhile() + endif() +endmacro() diff --git a/cmake/config/arm-linux.cmake b/cmake/config/arm-linux.cmake index 974b54114f..698b669a2d 100644 --- a/cmake/config/arm-linux.cmake +++ b/cmake/config/arm-linux.cmake @@ -12,11 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -include(CMakeForceCompiler) - set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR armv7l) -set(EXTERNAL_CMAKE_C_COMPILER arm-linux-gnueabihf-gcc) - -CMAKE_FORCE_C_COMPILER(${EXTERNAL_CMAKE_C_COMPILER} GNU) +set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc) +set(CMAKE_C_COMPILER_WORKS TRUE) diff --git a/cmake/config/arm-nuttx.cmake b/cmake/config/arm-nuttx.cmake index 86b1595719..d68aefd518 100644 --- a/cmake/config/arm-nuttx.cmake +++ b/cmake/config/arm-nuttx.cmake @@ -12,11 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -include(CMakeForceCompiler) - set(CMAKE_SYSTEM_NAME Nuttx) set(CMAKE_SYSTEM_PROCESSOR armv7l) -set(EXTERNAL_CMAKE_C_COMPILER arm-none-eabi-gcc) - -CMAKE_FORCE_C_COMPILER(${EXTERNAL_CMAKE_C_COMPILER} GNU) +set(CMAKE_C_COMPILER arm-none-eabi-gcc) +set(CMAKE_C_COMPILER_WORKS TRUE) diff --git a/cmake/config/arm-tizen.cmake b/cmake/config/arm-tizen.cmake index cf41e48657..56348b5ab4 100644 --- a/cmake/config/arm-tizen.cmake +++ b/cmake/config/arm-tizen.cmake @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -include(CMakeForceCompiler) - set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR armv7l) diff --git a/cmake/config/arm-tizenrt.cmake b/cmake/config/arm-tizenrt.cmake index df25d4a8e4..801a71e3f4 100644 --- a/cmake/config/arm-tizenrt.cmake +++ b/cmake/config/arm-tizenrt.cmake @@ -12,11 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -include(CMakeForceCompiler) - set(CMAKE_SYSTEM_NAME Tizenrt) set(CMAKE_SYSTEM_PROCESSOR armv7l) -set(EXTERNAL_CMAKE_C_COMPILER arm-none-eabi-gcc) - -CMAKE_FORCE_C_COMPILER(${EXTERNAL_CMAKE_C_COMPILER} GNU) +set(CMAKE_C_COMPILER arm-none-eabi-gcc) +set(CMAKE_C_COMPILER_WORKS TRUE) diff --git a/cmake/config/i686-linux.cmake b/cmake/config/i686-linux.cmake index c4c7f56197..0b7ab85664 100644 --- a/cmake/config/i686-linux.cmake +++ b/cmake/config/i686-linux.cmake @@ -12,7 +12,5 @@ # See the License for the specific language governing permissions and # limitations under the License. -include(CMakeForceCompiler) - set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR i686) diff --git a/cmake/config/i686-windows.cmake b/cmake/config/i686-windows.cmake new file mode 100644 index 0000000000..a7cea9d9a4 --- /dev/null +++ b/cmake/config/i686-windows.cmake @@ -0,0 +1,19 @@ +# Copyright 2015-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. + +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_SYSTEM_PROCESSOR i686) + +set(CMAKE_C_COMPILER CL.exe) +set(CMAKE_C_COMPILER_WORKS TRUE) diff --git a/cmake/config/mips-openwrt.cmake b/cmake/config/mips-openwrt.cmake new file mode 100644 index 0000000000..c61a34785a --- /dev/null +++ b/cmake/config/mips-openwrt.cmake @@ -0,0 +1,20 @@ +# 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. + +set(CMAKE_SYSTEM_NAME Openwrt) +set(CMAKE_SYSTEM_PROCESSOR mips) + +set(CMAKE_C_COMPILER mips-openwrt-linux-gcc) +set(CMAKE_C_COMPILER_WORKS TRUE) + diff --git a/config/tizenrt/artik05x/app/Make.defs b/cmake/config/noarch-linux.cmake similarity index 76% rename from config/tizenrt/artik05x/app/Make.defs rename to cmake/config/noarch-linux.cmake index da059d9259..a856848791 100644 --- a/config/tizenrt/artik05x/app/Make.defs +++ b/cmake/config/noarch-linux.cmake @@ -1,5 +1,4 @@ -# Copyright 2016-present Samsung Electronics Co., Ltd. and other contributors -# Copyright 2016 University of Szeged +# 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. @@ -13,6 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -ifeq ($(CONFIG_SYSTEM_IOTJS),y) -CONFIGURED_APPS += system/iotjs -endif +set(CMAKE_SYSTEM_NAME Linux) diff --git a/cmake/config/noarch-tizen.cmake b/cmake/config/noarch-tizen.cmake new file mode 100644 index 0000000000..509a2eed9b --- /dev/null +++ b/cmake/config/noarch-tizen.cmake @@ -0,0 +1,17 @@ +# 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(CMakeForceCompiler) + +set(CMAKE_SYSTEM_NAME Tizen) diff --git a/cmake/config/x86_64-darwin.cmake b/cmake/config/x86_64-darwin.cmake index e3c4bc431d..1952abe3f0 100644 --- a/cmake/config/x86_64-darwin.cmake +++ b/cmake/config/x86_64-darwin.cmake @@ -12,7 +12,5 @@ # See the License for the specific language governing permissions and # limitations under the License. -include(CMakeForceCompiler) - set(CMAKE_SYSTEM_NAME Darwin) set(CMAKE_SYSTEM_PROCESSOR x86_64) diff --git a/cmake/config/x86_64-linux.cmake b/cmake/config/x86_64-linux.cmake index 79cf370b74..2360b3a42f 100644 --- a/cmake/config/x86_64-linux.cmake +++ b/cmake/config/x86_64-linux.cmake @@ -12,7 +12,5 @@ # See the License for the specific language governing permissions and # limitations under the License. -include(CMakeForceCompiler) - set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR x86_64) diff --git a/cmake/config/x86_64-mock.cmake b/cmake/config/x86_64-mock.cmake new file mode 100644 index 0000000000..0a0a88ecda --- /dev/null +++ b/cmake/config/x86_64-mock.cmake @@ -0,0 +1,16 @@ +# 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. + +set(CMAKE_SYSTEM_NAME MockLinux) +set(CMAKE_SYSTEM_PROCESSOR x86_64) diff --git a/cmake/config/x86_64-windows.cmake b/cmake/config/x86_64-windows.cmake new file mode 100644 index 0000000000..4bc2e12cb9 --- /dev/null +++ b/cmake/config/x86_64-windows.cmake @@ -0,0 +1,19 @@ +# Copyright 2015-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. + +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_SYSTEM_PROCESSOR x64) + +set(CMAKE_C_COMPILER CL.exe) +set(CMAKE_C_COMPILER_WORKS TRUE) diff --git a/cmake/http-parser.cmake b/cmake/http-parser.cmake index 07f5671326..83f25798a0 100644 --- a/cmake/http-parser.cmake +++ b/cmake/http-parser.cmake @@ -18,6 +18,8 @@ if("${TARGET_OS}" MATCHES "NUTTX|TIZENRT") set(HTTPPARSER_NUTTX_ARG -DNUTTX_HOME=${TARGET_SYSTEMROOT}) endif() +build_lib_name(HTTPPARSER_NAME httpparser) + set(DEPS_HTTPPARSER deps/http-parser) set(DEPS_HTTPPARSER_SRC ${ROOT_DIR}/${DEPS_HTTPPARSER}/) ExternalProject_Add(http-parser @@ -26,8 +28,8 @@ ExternalProject_Add(http-parser BUILD_IN_SOURCE 0 BINARY_DIR ${DEPS_HTTPPARSER} INSTALL_COMMAND - ${CMAKE_COMMAND} -E copy - ${CMAKE_BINARY_DIR}/${DEPS_HTTPPARSER}/libhttpparser.a + ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_BINARY_DIR}/${DEPS_HTTPPARSER}/${CONFIG_TYPE}/ ${CMAKE_BINARY_DIR}/lib/ CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} @@ -35,12 +37,13 @@ ExternalProject_Add(http-parser -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} -DOS=${TARGET_OS} ${HTTPPARSER_NUTTX_ARG} + -DENABLE_MEMORY_CONSTRAINTS=ON ) add_library(libhttp-parser STATIC IMPORTED) add_dependencies(libhttp-parser http-parser) set_property(TARGET libhttp-parser PROPERTY - IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/libhttpparser.a) + IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/${HTTPPARSER_NAME}) set_property(DIRECTORY APPEND PROPERTY - ADDITIONAL_MAKE_CLEAN_FILES ${CMAKE_BINARY_DIR}/lib/libhttpparser.a) + ADDITIONAL_MAKE_CLEAN_FILES ${CMAKE_BINARY_DIR}/lib/${HTTPPARSER_NAME}) set(HTTPPARSER_INCLUDE_DIR ${DEPS_HTTPPARSER_SRC}) diff --git a/cmake/iotjs.cmake b/cmake/iotjs.cmake index 9e59905bca..b70b728f4b 100644 --- a/cmake/iotjs.cmake +++ b/cmake/iotjs.cmake @@ -14,79 +14,355 @@ cmake_minimum_required(VERSION 2.8) -set(IOTJS_SOURCE_DIR ${ROOT_DIR}/src) +if(NOT DEFINED PYTHON) + set(PYTHON "python") +endif() -function(find_value RESULT VALUE VALUE_TRUE VALUE_FALSE) - list(FIND ARGN ${VALUE} idx) - if(${idx} GREATER -1) - set(${RESULT} ${VALUE_TRUE} PARENT_SCOPE) - else() - set(${RESULT} ${VALUE_FALSE} PARENT_SCOPE) - endif() -endfunction(find_value) +include(${CMAKE_CURRENT_LIST_DIR}/JSONParser.cmake) -# System Configuration (not module) +set(IOTJS_SOURCE_DIR ${CMAKE_SOURCE_DIR}/src) + +# Platform configuration +# Look for files under src/platform// string(TOLOWER ${CMAKE_SYSTEM_NAME} IOTJS_SYSTEM_OS) set(PLATFORM_OS_DIR - ${IOTJS_SOURCE_DIR}/platform/${IOTJS_SYSTEM_OS}) -file(GLOB IOTJS_PLATFORM_SRC ${PLATFORM_OS_DIR}/iotjs_*.c) -file(GLOB PLATFORM_MODULE_SRC ${PLATFORM_OS_DIR}/iotjs_module_*.c) -if (IOTJS_PLATFORM_SRC AND PLATFORM_MODULE_SRC) - list(REMOVE_ITEM IOTJS_PLATFORM_SRC ${PLATFORM_MODULE_SRC}) -endif() + "${IOTJS_SOURCE_DIR}/platform/${IOTJS_SYSTEM_OS}") +file(GLOB IOTJS_PLATFORM_SRC "${PLATFORM_OS_DIR}/iotjs_*.c") -# Board Configuration (not module) -if(NOT "${TARGET_BOARD}" STREQUAL "None") - set(PLATFORM_BOARD_DIR - ${PLATFORM_OS_DIR}/${TARGET_BOARD}) - file(GLOB IOTJS_BOARD_SRC ${PLATFORM_BOARD_DIR}/iotjs_*.c) - file(GLOB PLATFORM_MODULE_SRC ${PLATFORM_BOARD_DIR}/iotjs_module_*.c) - if (IOTJS_BOARD_SRC AND PLATFORM_MODULE_SRC) - list(REMOVE_ITEM IOTJS_BOARD_SRC ${PLATFORM_MODULE_SRC}) +# Module configuration - listup all possible native C modules +function(getListOfVars prefix pattern varResult) + set(moduleNames) + get_cmake_property(vars VARIABLES) + string(REPLACE "." "\\." prefix ${prefix}) + foreach(var ${vars}) + string(REGEX MATCH + "(^|;)${prefix}${pattern}($|;)" + matchedVar "${var}") + if(matchedVar) + list(APPEND moduleNames ${CMAKE_MATCH_2}) + endif() + endforeach() + list(REMOVE_DUPLICATES moduleNames) + set(${varResult} ${moduleNames} PARENT_SCOPE) +endfunction() + +function(addModuleDependencies module varResult) + string(TOUPPER ${module} MODULE) + set(moduleDefines) + + set(MODULE_PREFIX ${IOTJS_MODULE_${MODULE}_JSON}.modules.${module}) + + if(NOT "${${MODULE_PREFIX}.require}" + STREQUAL "") + foreach(idx + ${${MODULE_PREFIX}.require}) + set(dependency + ${${MODULE_PREFIX}.require_${idx}}) + string(TOUPPER ${dependency} DEPENDENCY) + if(NOT ${ENABLE_MODULE_${DEPENDENCY}}) + list(APPEND moduleDefines ENABLE_MODULE_${DEPENDENCY}) + addModuleDependencies(${dependency} deps) + list(APPEND varResult ${deps}) + list(REMOVE_DUPLICATES varResult) + endif() + endforeach() endif() - list(APPEND IOTJS_PLATFORM_SRC ${IOTJS_BOARD_SRC}) -endif() -# Run js/native module analyzer -if(ENABLE_MINIMAL) - set(MODULE_ANALYZER_ARGS --iotjs-minimal-profile) + set(PLATFORM_REQUIRE_PREFIX ${MODULE_PREFIX}.platforms.${IOTJS_SYSTEM_OS}) + foreach(idx ${${PLATFORM_REQUIRE_PREFIX}.require}) + set(dependency ${${PLATFORM_REQUIRE_PREFIX}.require_${idx}}) + string(TOUPPER ${dependency} DEPENDENCY) + if (NOT ${ENABLE_MODULE_${DEPENDENCY}}) + list(APPEND moduleDefines ENABLE_MODULE_${DEPENDENCY}) + addModuleDependencies(${dependency} deps) + list(APPEND varResult ${deps}) + list(REMOVE_DUPLICATES varResult) + endif() + endforeach() + + set(${varResult} ${moduleDefines} PARENT_SCOPE) +endfunction() + +# Set the default profile if not specified +set(IOTJS_PROFILE "${CMAKE_SOURCE_DIR}/profiles/default.profile" + CACHE STRING "Path to profile.") + +if(NOT IS_ABSOLUTE ${IOTJS_PROFILE}) + set(IOTJS_PROFILE "${CMAKE_SOURCE_DIR}/${IOTJS_PROFILE}") endif() -execute_process( - COMMAND python ${ROOT_DIR}/tools/module_analyzer.py - --mode cmake-dump - --target-os ${TARGET_OS} - --iotjs-include-module "${IOTJS_INCLUDE_MODULE}" - --iotjs-exclude-module "${IOTJS_EXCLUDE_MODULE}" - ${MODULE_ANALYZER_ARGS} - RESULT_VARIABLE MODULE_ANALYZER_RETURN_CODE - ERROR_VARIABLE MODULE_ANALYZER_OUTPUT_ERR - OUTPUT_VARIABLE MODULE_ANALYZER_OUTPUT -) +# Enable the modules defined by the profile +if(EXISTS ${IOTJS_PROFILE}) + file(READ "${IOTJS_PROFILE}" PROFILE_SETTINGS) + string(REGEX REPLACE "^#.*$" "" PROFILE_SETTINGS "${PROFILE_SETTINGS}") + string(REGEX REPLACE "[\r|\n]" ";" PROFILE_SETTINGS "${PROFILE_SETTINGS}") -if(MODULE_ANALYZER_RETURN_CODE) - message(FATAL_ERROR - "Error during module analyzer execution (${MODULE_ANALYZER_RETURN_CODE}): " - "${MODULE_ANALYZER_OUTPUT}" - "${MODULE_ANALYZER_OUTPUT_ERR}") + foreach(module_define ${PROFILE_SETTINGS}) + set(${module_define} ON CACHE BOOL "ON/OFF") + endforeach() +else() + message(FATAL_ERROR "Profile file: '${IOTJS_PROFILE}' doesn't exist!") endif() -if(VERBOSE) - message("Module analyzer:\n${MODULE_ANALYZER_OUTPUT}") +set(IOTJS_MODULES) +set(MODULES_INCLUDE_DIR) + +# Add the basic descriptor file (src/modules.json) +list(APPEND EXTERNAL_MODULES ${IOTJS_SOURCE_DIR}) + +set(iotjs_module_idx 0) +foreach(module_descriptor ${EXTERNAL_MODULES}) + get_filename_component(MODULE_DIR ${module_descriptor} ABSOLUTE) + + if(NOT EXISTS "${MODULE_DIR}/modules.json") + message(FATAL_ERROR "The modules.json file doesn't exist in ${MODULE_DIR}") + endif() + + list(APPEND MODULES_INCLUDE_DIR ${MODULE_DIR}) + list(APPEND IOTJS_MODULES_JSONS "${iotjs_module_idx}") + set(CURR_JSON "IOTJS_MODULES_JSON_${iotjs_module_idx}") + set(${CURR_JSON}_PATH ${MODULE_DIR}) + + file(READ "${MODULE_DIR}/modules.json" IOTJS_MODULES_JSON_FILE) + sbeParseJson(${CURR_JSON} IOTJS_MODULES_JSON_FILE) + getListOfVars("${CURR_JSON}.modules." "([A-Za-z0-9_]+)[A-Za-z0-9_.]*" + _IOTJS_MODULES) + list(APPEND IOTJS_MODULES ${_IOTJS_MODULES}) + + foreach(module ${_IOTJS_MODULES}) + string(TOUPPER ${module} MODULE) + set(IOTJS_MODULE_${MODULE}_JSON ${CURR_JSON}) + endforeach() + + math(EXPR iotjs_module_idx "${iotjs_module_idx} + 1") +endforeach(module_descriptor) + +list(REMOVE_DUPLICATES IOTJS_MODULES) + +# Turn off the other modules +foreach(module ${IOTJS_MODULES}) + string(TOUPPER ${module} MODULE) + set(ENABLE_MODULE_${MODULE} OFF CACHE BOOL "ON/OFF") +endforeach() + +# Resolve the dependencies and set the ENABLE_MODULE_[NAME] variables +foreach(module ${IOTJS_MODULES}) + string(TOUPPER ${module} MODULE) + if(${ENABLE_MODULE_${MODULE}}) + addModuleDependencies(${module} deps) + foreach(module_define ${deps}) + set(${module_define} ON) + endforeach() + unset(deps) + endif() +endforeach() + +set(IOTJS_JS_MODULES) +set(IOTJS_JS_MODULE_SRC) +set(IOTJS_NATIVE_MODULES) +set(IOTJS_NATIVE_MODULE_SRC) +set(IOTJS_MODULE_DEFINES) + +message("IoT.js module configuration:") +getListOfVars("ENABLE_MODULE_" "([A-Za-z0-9_]+)" IOTJS_ENABLED_MODULES) +foreach(MODULE ${IOTJS_ENABLED_MODULES}) + set(MODULE_DEFINE_VAR "ENABLE_MODULE_${MODULE}") + message(STATUS "${MODULE_DEFINE_VAR} = ${${MODULE_DEFINE_VAR}}") + # Set the defines for build + if(${MODULE_DEFINE_VAR}) + list(APPEND IOTJS_MODULE_DEFINES "-D${MODULE_DEFINE_VAR}=1") + else() + list(APPEND IOTJS_MODULE_DEFINES "-D${MODULE_DEFINE_VAR}=0") + endif() +endforeach() + +set(EXTRA_CMAKE_FILES) + +# Collect the files of enabled modules +foreach(MODULE ${IOTJS_ENABLED_MODULES}) + if(${ENABLE_MODULE_${MODULE}}) + string(TOLOWER ${MODULE} module) + set(IOTJS_MODULES_JSON ${IOTJS_MODULE_${MODULE}_JSON}) + set(MODULE_BASE_DIR ${${IOTJS_MODULES_JSON}_PATH}) + set(MODULE_PREFIX ${IOTJS_MODULES_JSON}.modules.${module}.) + + # Add js source + set(MODULE_JS_FILE ${${MODULE_PREFIX}js_file}) + if(NOT "${MODULE_JS_FILE}" STREQUAL "") + set(JS_PATH "${MODULE_BASE_DIR}/${MODULE_JS_FILE}") + if(EXISTS "${JS_PATH}") + list(APPEND IOTJS_JS_MODULES "${module}=${JS_PATH}") + list(APPEND IOTJS_JS_MODULE_SRC ${JS_PATH}) + else() + message(FATAL_ERROR "JS file doesn't exist: ${JS_PATH}") + endif() + endif() + + # Check extra cmake file + set(EXTRA_CMAKE_FILE ${${MODULE_PREFIX}cmakefile}) + if(NOT "${EXTRA_CMAKE_FILE}" STREQUAL "") + set(EXTRA_CMAKE_FILE_PATH "${MODULE_BASE_DIR}/${EXTRA_CMAKE_FILE}") + if(EXISTS "${EXTRA_CMAKE_FILE_PATH}") + list(APPEND EXTRA_CMAKE_FILES "${EXTRA_CMAKE_FILE_PATH}") + else() + message(FATAL_ERROR + "CMake file doesn't exists: ${EXTRA_CMAKE_FILE_PATH}") + endif() + endif() + + # Add platform-related native source + if(NOT "${${MODULE_PREFIX}native_files}" STREQUAL "" + AND NOT "${${MODULE_PREFIX}init}" STREQUAL "") + list(APPEND IOTJS_NATIVE_MODULES "${MODULE}") + endif() + + # Add common native source + foreach(idx ${${MODULE_PREFIX}native_files}) + set(MODULE_C_FILE + ${${MODULE_PREFIX}native_files_${idx}}) + set(MODULE_C_FILE "${MODULE_BASE_DIR}/${MODULE_C_FILE}") + if(EXISTS "${MODULE_C_FILE}") + list(APPEND IOTJS_NATIVE_MODULE_SRC ${MODULE_C_FILE}) + else() + message(FATAL_ERROR "C file doesn't exist: ${MODULE_C_FILE}") + endif() + endforeach() + + # Add external libraries + foreach(idx ${${MODULE_PREFIX}external_libs}) + list(APPEND EXTERNAL_LIBS + ${${MODULE_PREFIX}external_libs_${idx}}) + endforeach() + + getListOfVars("${MODULE_PREFIX}" "([A-Za-z0-9_]+[A-Za-z])[A-Za-z0-9_.]*" + MODULE_KEYS) + list(FIND MODULE_KEYS "platforms" PLATFORMS_KEY) + + set(PLATFORMS_PREFIX ${MODULE_PREFIX}platforms.) + if(${PLATFORMS_KEY} GREATER -1) + getListOfVars("${PLATFORMS_PREFIX}" + "([A-Za-z0-9_]+[A-Za-z])[A-Za-z0-9_.]*" MODULE_PLATFORMS) + list(FIND MODULE_PLATFORMS ${IOTJS_SYSTEM_OS} PLATFORM_NATIVES) + + # Add plaform-dependant information + if(${PLATFORM_NATIVES} GREATER -1) + # native source if exists... + foreach(idx ${${PLATFORMS_PREFIX}${IOTJS_SYSTEM_OS}.native_files}) + set(MODULE_PLATFORM_FILE + ${${PLATFORMS_PREFIX}${IOTJS_SYSTEM_OS}.native_files_${idx}}) + set(MODULE_PLATFORM_FILE "${MODULE_BASE_DIR}/${MODULE_PLATFORM_FILE}") + if(EXISTS "${MODULE_PLATFORM_FILE}") + list(APPEND IOTJS_NATIVE_MODULE_SRC ${MODULE_PLATFORM_FILE}) + else() + message(FATAL_ERROR "C file doesn't exist: ${MODULE_PLATFORM_FILE}") + endif() + endforeach() + + # external libraries.... + foreach(idx ${${PLATFORMS_PREFIX}${IOTJS_SYSTEM_OS}.external_libs}) + list(APPEND EXTERNAL_LIBS + ${${PLATFORMS_PREFIX}${IOTJS_SYSTEM_OS}.external_libs_${idx}}) + endforeach() + # ...otherwise from 'undefined' section. + else() + # add native files + foreach(idx ${${PLATFORMS_PREFIX}undefined.native_files}) + set(MODULE_UNDEFINED_FILE + "${${MODULE_PREFIX}undefined.native_files_${idx}}") + set(MODULE_UNDEFINED_FILE + "${MODULE_BASE_DIR}/${MODULE_UNDEFINED_FILE}") + if(EXISTS "${MODULE_UNDEFINED_FILE}") + list(APPEND IOTJS_NATIVE_MODULE_SRC ${MODULE_UNDEFINED_FILE}) + else() + message(FATAL_ERROR "${MODULE_UNDEFINED_FILE} does not exists.") + endif() + endforeach() + + # external libraries.... + foreach(idx ${${PLATFORMS_PREFIX}undefined.external_libs}) + list(APPEND EXTERNAL_LIBS + ${${PLATFORMS_PREFIX}undefined.external_libs_${idx}}) + endforeach() + endif() + endif() + endif() +endforeach(MODULE) + +list(APPEND IOTJS_JS_MODULES "iotjs=${IOTJS_SOURCE_DIR}/js/iotjs.js") + +# Generate src/iotjs_module_inl.h +# Build up init function prototypes +set(IOTJS_MODULE_INITIALIZERS "") +foreach(MODULE ${IOTJS_NATIVE_MODULES}) + set(IOTJS_MODULES_JSON ${IOTJS_MODULE_${MODULE}_JSON}) + string(TOLOWER ${MODULE} module) + + set(IOTJS_MODULE_INITIALIZERS "${IOTJS_MODULE_INITIALIZERS} +extern jerry_value_t ${${IOTJS_MODULES_JSON}.modules.${module}.init}(void);") +endforeach() + +# Build up module entries +set(IOTJS_MODULE_ENTRIES "") +set(IOTJS_MODULE_OBJECTS "") +foreach(MODULE ${IOTJS_NATIVE_MODULES}) + set(IOTJS_MODULES_JSON ${IOTJS_MODULE_${MODULE}_JSON}) + string(TOLOWER ${MODULE} module) + set(INIT_FUNC ${${IOTJS_MODULES_JSON}.modules.${module}.init}) + + set(IOTJS_MODULE_ENTRIES "${IOTJS_MODULE_ENTRIES} + { \"${module}\", ${INIT_FUNC} },") + set(IOTJS_MODULE_OBJECTS "${IOTJS_MODULE_OBJECTS} + { 0 },") +endforeach() + +# Build up the contents of src/iotjs_module_inl.h +list(LENGTH IOTJS_NATIVE_MODULES IOTJS_MODULE_COUNT) +set(IOTJS_MODULE_INL_H "/* File generated via iotjs.cmake */ +${IOTJS_MODULE_INITIALIZERS} + +const unsigned iotjs_module_count = ${IOTJS_MODULE_COUNT}; + +const +iotjs_module_ro_data_t iotjs_module_ro_data[${IOTJS_MODULE_COUNT}] = { +${IOTJS_MODULE_ENTRIES} +}; + +iotjs_module_rw_data_t iotjs_module_rw_data[${IOTJS_MODULE_COUNT}] = { +${IOTJS_MODULE_OBJECTS} +}; +") + +file(WRITE ${IOTJS_SOURCE_DIR}/iotjs_module_inl.h "${IOTJS_MODULE_INL_H}") + +# Cleanup +unset(IOTJS_MODULE_INL_H) +unset(IOTJS_MODULES_JSON_FILE) + +foreach(idx ${IOTJS_MODULES_JSONS}) + sbeClearJson(IOTJS_MODULES_JSON_${idx}) + unset(IOTJS_MODULES_JSON_${idx}_PATH) +endforeach() + +foreach(module ${IOTJS_MODULES}) + string(TOUPPER ${module} MODULE) + unset(IOTJS_MODULE_${MODULE}_JSON) +endforeach() + +# Common compile flags +iotjs_add_compile_flags(-Wall) +if(NOT USING_MSVC) + iotjs_add_compile_flags(-Wextra -Werror -Wno-unused-parameter) + iotjs_add_compile_flags(-Wsign-conversion -std=gnu99) endif() -function(get_variable_value OUTPUT_VAR VAR_NAME STRING_DATA) - string(REGEX MATCHALL "${VAR_NAME}=[a-zA-Z;_0-9-]+" LINE "${STRING_DATA}") - string(REPLACE "${VAR_NAME}=" "" VAR_VALUE "${LINE}") - string(STRIP "${VAR_VALUE}" VAR_VALUE) - separate_arguments(VAR_VALUE) - set(${OUTPUT_VAR} ${VAR_VALUE} PARENT_SCOPE) -endfunction(get_variable_value) +if(ENABLE_SNAPSHOT) + set(JS2C_SNAPSHOT_ARG --snapshot-tool=${JERRY_HOST_SNAPSHOT}) + iotjs_add_compile_flags(-DENABLE_SNAPSHOT) +endif() -get_variable_value(IOTJS_NATIVE_MODULES - "IOTJS_NATIVE_MODULES" "${MODULE_ANALYZER_OUTPUT}") -get_variable_value(IOTJS_JS_MODULES - "IOTJS_JS_MODULES" "${MODULE_ANALYZER_OUTPUT}") +if (EXPOSE_GC) + iotjs_add_compile_flags(-DEXPOSE_GC) +endif() # Run js2c set(JS2C_RUN_MODE "release") @@ -94,185 +370,226 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") set(JS2C_RUN_MODE "debug") endif() -if(ENABLE_SNAPSHOT) - set(JS2C_SNAPSHOT_ARG --snapshot-generator=${JERRY_HOST}) - set(IOTJS_CFLAGS ${IOTJS_CFLAGS} -DENABLE_SNAPSHOT) +if(USING_MSVC) + set(JS2C_PREPROCESS_ARGS /EP /d1PP) +else() + set(JS2C_PREPROCESS_ARGS -E -dD) endif() +string (REPLACE ";" "," IOTJS_JS_MODULES_STR "${IOTJS_JS_MODULES}") add_custom_command( OUTPUT ${IOTJS_SOURCE_DIR}/iotjs_js.c ${IOTJS_SOURCE_DIR}/iotjs_js.h - COMMAND python ${ROOT_DIR}/tools/js2c.py + COMMAND ${CMAKE_C_COMPILER} ${JS2C_PREPROCESS_ARGS} ${IOTJS_MODULE_DEFINES} + ${IOTJS_SOURCE_DIR}/iotjs_magic_strings.h + > ${IOTJS_SOURCE_DIR}/iotjs_magic_strings.in + COMMAND ${PYTHON} ${ROOT_DIR}/tools/js2c.py ARGS --buildtype=${JS2C_RUN_MODE} - --modules '${IOTJS_JS_MODULES}' + --modules "${IOTJS_JS_MODULES_STR}" ${JS2C_SNAPSHOT_ARG} + COMMAND ${CMAKE_COMMAND} -E remove + -f ${IOTJS_SOURCE_DIR}/iotjs_magic_strings.in DEPENDS ${ROOT_DIR}/tools/js2c.py - jerry - ${IOTJS_SOURCE_DIR}/js/*.js + jerry-snapshot + ${IOTJS_JS_MODULE_SRC} ) -# Module Configuration - listup all possible native C modules -set(IOTJS_MODULES_ENABLED) -set(IOTJS_MODULES_DISABLED) -# List all modules and mark them as disabled by default -file(GLOB IOTJS_MODULES_ALL_SRC ${IOTJS_SOURCE_DIR}/modules/*.c) -foreach(module ${IOTJS_MODULES_ALL_SRC}) - ## iotjs_module_adc.c -> ADC - get_filename_component(IOTJS_MODULENAME ${module} NAME_WE) - string(SUBSTRING ${IOTJS_MODULENAME} 13 -1 IOTJS_MODULENAME) - string(TOUPPER ${IOTJS_MODULENAME} IOTJS_MODULENAME) - list(APPEND IOTJS_MODULES_DISABLED ${IOTJS_MODULENAME}) -endforeach() +# Load all external module cmake files +foreach(MODULE_EXTRA_CMAKE_FILE ${EXTRA_CMAKE_FILES}) + message("Using CMake file: ${MODULE_EXTRA_CMAKE_FILE}") -# Module Configuration - enable only selected modules and add board support -set(IOTJS_PLATFORM_SUPPORT) -set(IOTJS_BOARD_SUPPORT) -set(IOTJS_MODULES_SRC) -set(PLATFORM_SRC - ${IOTJS_SOURCE_DIR}/platform/${PLATFORM_DESCRIPTOR}/iotjs_module) -foreach(module ${IOTJS_NATIVE_MODULES}) - string(TOUPPER ${module} MODULE) - # check if there is a native file for the module - set(BASE_MODULE_SRC ${IOTJS_SOURCE_DIR}/modules/iotjs_module_${module}.c) - if(EXISTS "${BASE_MODULE_SRC}") - list(APPEND IOTJS_MODULE_SRC ${BASE_MODULE_SRC}) - endif() + set(MODULE_BINARY_DIR ${CMAKE_BINARY_DIR}/external/) + set(MODULE_LIBS) + get_filename_component(MODULE_DIR ${MODULE_EXTRA_CMAKE_FILE} DIRECTORY) - # first, check if there is the module in / - set(ADD_MODULE_RESULT FALSE) - if(NOT "${TARGET_BOARD}" STREQUAL "None") - set(PLATFORM_MODULE_SRC ${PLATFORM_BOARD_DIR}/iotjs_module_${module}) - set(PLATFORM_MODULE_SRC - ${PLATFORM_MODULE_SRC}-${IOTJS_SYSTEM_OS}-${TARGET_BOARD}.c) - if(EXISTS "${PLATFORM_MODULE_SRC}") - list(APPEND IOTJS_MODULE_SRC ${PLATFORM_MODULE_SRC}) - list(APPEND IOTJS_BOARD_SUPPORT ${MODULE}) - set(${ADD_MODULE_RESULT} TRUE) - else() - set(${ADD_MODULE_RESULT} FALSE) - endif() - endif() + # Variables which should be used by the external module(s): + # - MODULE_DIR - the modules root directory + # - MODULE_BINARY_DIR - the build directory for the current module + # - MODULE_LIBS - list of libraries to use during linking (set this) + include(${MODULE_EXTRA_CMAKE_FILE}) - # if the module is not in /, look in - if(NOT ${ADD_MODULE_RESULT}) - set(PLATFORM_MODULE_SRC - ${PLATFORM_OS_DIR}/iotjs_module_${module}-${IOTJS_SYSTEM_OS}.c) - if(EXISTS "${PLATFORM_MODULE_SRC}") - list(APPEND IOTJS_MODULE_SRC ${PLATFORM_MODULE_SRC}) - list(APPEND IOTJS_PLATFORM_SUPPORT ${MODULE}) - endif() + if (NOT MODULE_NAME) + message(FATAL_ERROR + "MODULE_NAME was not specified in ${MODULE_EXTRA_CMAKE_FILE}") endif() - list(APPEND IOTJS_MODULES_ENABLED ${MODULE}) - list(REMOVE_ITEM IOTJS_MODULES_DISABLED ${MODULE}) -endforeach() -# Build the module enable defines and print out the module configurations -message("Native module configuration:") -set(IOTJS_MODULES_ALL ${IOTJS_MODULES_ENABLED} ${IOTJS_MODULES_DISABLED}) -list(SORT IOTJS_MODULES_ALL) -foreach(module ${IOTJS_MODULES_ALL}) - find_value(MODULE_ENABLED "${module}" 1 0 ${IOTJS_MODULES_ENABLED}) - list(APPEND IOTJS_CFLAGS "-DENABLE_MODULE_${module}=${MODULE_ENABLED}") - - if(MODULE_ENABLED) - find_value(PLATFORM_SUPPORT "${module}" "found" "NOT found" - ${IOTJS_PLATFORM_SUPPORT}) - if(DEFINED TARGET_BOARD) - find_value(BOARD_SUPPORT "${module}" "found" "NOT found" - ${IOTJS_BOARD_SUPPORT}) - set(BOARD_SUPPORT_STR "[Board support: ${BOARD_SUPPORT}]") - else() - set(BOARD_SUPPORT_STR "") - endif() + list(APPEND EXTERNAL_LIBS ${MODULE_LIBS}) - message(STATUS "${module}: ON " - "[Platform support: ${PLATFORM_SUPPORT}]" - "${BOARD_SUPPORT_STR}") - else() - message(STATUS "${module}: OFF") - endif() + # Just to make sure it will always be unset + unset(MODULE_NAME) # This is usually set by the included cmake file + unset(MODULE_BINARY_DIR) + unset(MODULE_LIBS) endforeach() -# List the enabled js modules -message("Enabled JS modules:") -foreach(module ${IOTJS_JS_MODULES}) - message(STATUS "${module}") -endforeach() - -# Print out some configs -message("IoT.js configured with:") -message(STATUS "CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE}") -message(STATUS "CMAKE_C_FLAGS ${CMAKE_C_FLAGS}") -message(STATUS "PLATFORM_DESCRIPTOR ${PLATFORM_DESCRIPTOR}") -message(STATUS "TARGET_OS ${TARGET_OS}") -message(STATUS "TARGET_SYSTEMROOT ${TARGET_SYSTEMROOT}") -message(STATUS "TARGET_BOARD ${TARGET_BOARD}") -message(STATUS "BUILD_LIB_ONLY ${BUILD_LIB_ONLY}") -message(STATUS "ENABLE_LTO ${ENABLE_LTO}") -message(STATUS "ENABLE_SNAPSHOT ${ENABLE_SNAPSHOT}") -message(STATUS "ENABLE_MINIMAL ${ENABLE_MINIMAL}") -message(STATUS "IOTJS_INCLUDE_MODULE ${IOTJS_INCLUDE_MODULE}") -message(STATUS "IOTJS_EXCLUDE_MODULE ${IOTJS_EXCLUDE_MODULE}") -message(STATUS "IOTJS_C_FLAGS ${IOTJS_C_FLAGS}") -message(STATUS "IOTJS_LINK_FLAGS ${IOTJS_LINK_FLAGS}") - # Collect all sources into LIB_IOTJS_SRC file(GLOB LIB_IOTJS_SRC ${IOTJS_SOURCE_DIR}/*.c) list(APPEND LIB_IOTJS_SRC ${IOTJS_SOURCE_DIR}/iotjs_js.c ${IOTJS_SOURCE_DIR}/iotjs_js.h - ${IOTJS_MODULE_SRC} + ${IOTJS_NATIVE_MODULE_SRC} ${IOTJS_PLATFORM_SRC} ) separate_arguments(EXTERNAL_INCLUDE_DIR) -separate_arguments(EXTERNAL_STATIC_LIB) -separate_arguments(EXTERNAL_SHARED_LIB) +separate_arguments(EXTERNAL_LIBS) set(IOTJS_INCLUDE_DIRS ${EXTERNAL_INCLUDE_DIR} ${ROOT_DIR}/include ${IOTJS_SOURCE_DIR} + ${MODULES_INCLUDE_DIR} + ${PLATFORM_OS_DIR} ${JERRY_PORT_DIR}/include + ${JERRY_EXT_DIR}/include ${JERRY_INCLUDE_DIR} ${HTTPPARSER_INCLUDE_DIR} + ${MBEDTLS_INCLUDE_DIR} ${TUV_INCLUDE_DIR} ) -set(IOTJS_CFLAGS ${IOTJS_CFLAGS} ${CFLAGS_COMMON}) +if(NOT BUILD_LIB_ONLY) + if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin") + iotjs_add_link_flags("-Xlinker -map -Xlinker iotjs.map") + elseif(USING_MSVC) + iotjs_add_link_flags("/MAP:iotjs.map") + else() + iotjs_add_link_flags("-Xlinker -Map -Xlinker iotjs.map") + endif() +endif() -# Configure the libiotjs.a +# Print out some configs +message("IoT.js configured with:") +message(STATUS "BUILD_LIB_ONLY ${BUILD_LIB_ONLY}") +message(STATUS "CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE}") +message(STATUS "CMAKE_C_FLAGS ${CMAKE_C_FLAGS}") +message(STATUS "CMAKE_TOOLCHAIN_FILE ${CMAKE_TOOLCHAIN_FILE}") +message(STATUS "ENABLE_LTO ${ENABLE_LTO}") +message(STATUS "ENABLE_SNAPSHOT ${ENABLE_SNAPSHOT}") +message(STATUS "EXPOSE_GC ${EXPOSE_GC}") +message(STATUS "EXTERNAL_INCLUDE_DIR ${EXTERNAL_INCLUDE_DIR}") +message(STATUS "EXTERNAL_LIBC_INTERFACE ${EXTERNAL_LIBC_INTERFACE}") +message(STATUS "EXTERNAL_LIBS ${EXTERNAL_LIBS}") +message(STATUS "EXTERNAL_MODULES ${EXTERNAL_MODULES}") +message(STATUS "IOTJS_LINKER_FLAGS ${IOTJS_LINKER_FLAGS}") +message(STATUS "IOTJS_PROFILE ${IOTJS_PROFILE}") +message(STATUS "JERRY_DEBUGGER ${JERRY_DEBUGGER}") +message(STATUS "JERRY_GLOBAL_HEAP_SIZE ${JERRY_GLOBAL_HEAP_SIZE}") +message(STATUS "JERRY_MEM_STATS ${JERRY_MEM_STATS}") +message(STATUS "JERRY_PROFILE ${JERRY_PROFILE}") +message(STATUS "TARGET_ARCH ${TARGET_ARCH}") +message(STATUS "TARGET_BOARD ${TARGET_BOARD}") +message(STATUS "TARGET_OS ${TARGET_OS}") +message(STATUS "TARGET_SYSTEMROOT ${TARGET_SYSTEMROOT}") + +iotjs_add_compile_flags(${IOTJS_MODULE_DEFINES}) + +if(JERRY_DEBUGGER) + iotjs_add_compile_flags("-DJERRY_DEBUGGER") +endif() + +file(GLOB IOTJS_HEADERS "${ROOT_DIR}/src/*.h") +file(GLOB JERRY_HEADERS "${ROOT_DIR}/deps/jerry/jerry-core/include/*.h") +file(GLOB LIBUV_HEADERS "${ROOT_DIR}/deps/libtuv/include/*.h") + +set(IOTJS_PUBLIC_HEADERS + "include/iotjs.h" + "include/node_api.h" + "include/node_api_types.h" + ${IOTJS_HEADERS} + ${JERRY_HEADERS} + ${LIBUV_HEADERS} +) + +# Configure the libiotjs set(TARGET_LIB_IOTJS libiotjs) -add_library(${TARGET_LIB_IOTJS} STATIC ${LIB_IOTJS_SRC}) +if(CREATE_SHARED_LIB) + add_library(${TARGET_LIB_IOTJS} SHARED ${LIB_IOTJS_SRC}) +else() + add_library(${TARGET_LIB_IOTJS} STATIC ${LIB_IOTJS_SRC}) + + # FIXME: module specific condition should not be in the main cmake + if(${ENABLE_MODULE_NAPI}) + # Some tests require the GC to be exposed + iotjs_add_compile_flags(-DEXPOSE_GC) + + # Force symbols to be entered in the output file as undefined symbols. + file(READ "${IOTJS_SOURCE_DIR}/napi/node_symbols.txt" NODE_SYMBOLS) + string(REGEX REPLACE "[\r|\n]" ";" NODE_SYMBOLS "${NODE_SYMBOLS}") + + if(USING_MSVC) + set(NODE_SYMBOL_SEPARATOR " /INCLUDE:") + if("${TARGET_ARCH}" STREQUAL "i686") + set(NODE_SYMBOL_SEPARATOR "${NODE_SYMBOL_SEPARATOR}_") + endif() + else() + set(NODE_SYMBOLS_LINK_FLAGS "-Wl") + set(NODE_SYMBOL_SEPARATOR ",-u,") + endif() + + foreach(NODE_SYMBOL ${NODE_SYMBOLS}) + set(NODE_SYMBOLS_LINK_FLAGS + "${NODE_SYMBOLS_LINK_FLAGS}${NODE_SYMBOL_SEPARATOR}${NODE_SYMBOL}") + endforeach() + + iotjs_add_link_flags(${NODE_SYMBOLS_LINK_FLAGS}) + endif() +endif(CREATE_SHARED_LIB) + +add_dependencies(${TARGET_LIB_IOTJS} + ${JERRY_LIBS} + ${TUV_LIBS} + libhttp-parser + ${MBEDTLS_LIBS} +) + set_target_properties(${TARGET_LIB_IOTJS} PROPERTIES - COMPILE_OPTIONS "${IOTJS_CFLAGS}" OUTPUT_NAME iotjs ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" + PUBLIC_HEADER "${IOTJS_PUBLIC_HEADERS}" ) -target_include_directories(${TARGET_LIB_IOTJS} PRIVATE ${IOTJS_INCLUDE_DIRS}) +target_include_directories(${TARGET_LIB_IOTJS} + PRIVATE ${IOTJS_INCLUDE_DIRS}) target_link_libraries(${TARGET_LIB_IOTJS} + ${CMAKE_DL_LIBS} ${JERRY_LIBS} ${TUV_LIBS} libhttp-parser - ${EXTERNAL_STATIC_LIB} - ${EXTERNAL_SHARED_LIB} + ${MBEDTLS_LIBS} + ${EXTERNAL_LIBS} ) -if(NOT BUILD_LIB_ONLY) +if("${LIB_INSTALL_DIR}" STREQUAL "") + set(LIB_INSTALL_DIR "lib") +endif() - if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin") - set(IOTJS_LINK_FLAGS "-Xlinker -map -Xlinker iotjs.map") - else() - set(IOTJS_LINK_FLAGS "-Xlinker -Map -Xlinker iotjs.map") - endif() +if("${BIN_INSTALL_DIR}" STREQUAL "") + set(BIN_INSTALL_DIR "bin") +endif() - # Configure the iotjs executable +if("${INC_INSTALL_DIR}" STREQUAL "") + set(INC_INSTALL_DIR "include/iotjs") +endif() + +# Configure the iotjs executable +if(NOT BUILD_LIB_ONLY) set(TARGET_IOTJS iotjs) - add_executable(${TARGET_IOTJS} ${ROOT_DIR}/iotjs_linux.c) + message(STATUS "CMAKE_BINARY_DIR ${CMAKE_BINARY_DIR}") + message(STATUS "BINARY_INSTALL_DIR ${INSTALL_PREFIX}/${BIN_INSTALL_DIR}") + message(STATUS "LIBRARY_INSTALL_DIR ${INSTALL_PREFIX}/${LIB_INSTALL_DIR}") + message(STATUS "INCLUDE_INSTALL_DIR ${INSTALL_PREFIX}/${INC_INSTALL_DIR}") + + add_executable(${TARGET_IOTJS} ${ROOT_DIR}/src/platform/linux/iotjs_linux.c) set_target_properties(${TARGET_IOTJS} PROPERTIES - COMPILE_OPTIONS "${IOTJS_CFLAGS}" - LINK_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${IOTJS_LINK_FLAGS}" + LINK_FLAGS "${IOTJS_LINKER_FLAGS}" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" ) target_include_directories(${TARGET_IOTJS} PRIVATE ${IOTJS_INCLUDE_DIRS}) target_link_libraries(${TARGET_IOTJS} ${TARGET_LIB_IOTJS}) + install(TARGETS ${TARGET_IOTJS} ${TARGET_LIB_IOTJS} + RUNTIME DESTINATION "${BIN_INSTALL_DIR}" + ARCHIVE DESTINATION "${LIB_INSTALL_DIR}" + LIBRARY DESTINATION "${LIB_INSTALL_DIR}" + PUBLIC_HEADER DESTINATION "${INC_INSTALL_DIR}") +else() + install(TARGETS ${TARGET_LIB_IOTJS} DESTINATION ${LIB_INSTALL_DIR}) endif() diff --git a/cmake/jerry.cmake b/cmake/jerry.cmake index ee7d9ece6f..b86ab9f166 100644 --- a/cmake/jerry.cmake +++ b/cmake/jerry.cmake @@ -21,20 +21,38 @@ ExternalProject_Add(hostjerry SOURCE_DIR ${ROOT_DIR}/deps/jerry/ BUILD_IN_SOURCE 0 BINARY_DIR ${DEPS_HOST_JERRY} - INSTALL_COMMAND "" CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} - -DJERRY_LIBC=OFF - -DJERRY_CMDLINE=ON - -DJERRY_CMDLINE_MINIMAL=OFF - -DFEATURE_SNAPSHOT_SAVE=${ENABLE_SNAPSHOT} - -DFEATURE_PROFILE=es5.1 + -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/${DEPS_HOST_JERRY} + -DENABLE_AMALGAM=ON + -DENABLE_LTO=${ENABLE_LTO} + -DJERRY_CMDLINE=OFF + -DJERRY_CMDLINE_SNAPSHOT=ON + -DJERRY_EXT=ON + -DJERRY_LOGGING=ON + -DJERRY_ERROR_MESSAGES=ON + -DJERRY_SNAPSHOT_SAVE=${ENABLE_SNAPSHOT} + -DJERRY_PROFILE=${JERRY_PROFILE} + -DJERRY_LINE_INFO=${JERRY_LINE_INFO} + ${EXTRA_JERRY_CMAKE_PARAMS} + + # The snapshot tool does not require the system allocator + # turn it off by default. + # + # Additionally this is required if one compiles on a + # 64bit system to a 32bit system with system allocator + # enabled. This is beacuse on 64bit the system allocator + # should not be used as it returns 64bit pointers which + # can not be represented correctly in the JerryScript engine + # currently. + -DJERRY_SYSTEM_ALLOCATOR=OFF ) -add_executable(jerry IMPORTED) -add_dependencies(jerry hostjerry) -set_property(TARGET jerry PROPERTY - IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/${DEPS_HOST_JERRY}/bin/jerry) -set(JERRY_HOST ${CMAKE_BINARY_DIR}/${DEPS_HOST_JERRY}/bin/jerry) +set(JERRY_HOST_SNAPSHOT + ${CMAKE_BINARY_DIR}/${DEPS_HOST_JERRY}/bin/jerry-snapshot) +add_executable(jerry-snapshot IMPORTED) +add_dependencies(jerry-snapshot hostjerry) +set_property(TARGET jerry-snapshot PROPERTY + IMPORTED_LOCATION ${JERRY_HOST_SNAPSHOT}) # Utility method to add -D= macro(add_cmake_arg TARGET_ARG KEY) @@ -44,7 +62,7 @@ macro(add_cmake_arg TARGET_ARG KEY) endmacro(add_cmake_arg) # Target libjerry -set(JERRY_LIBS jerry-core jerry-port-default) +set(JERRY_LIBS jerry-core jerry-port-default jerry-ext) set(DEPS_LIB_JERRY_ARGS) # Configure the MinSizeRel as the default build type @@ -56,49 +74,53 @@ else() endif() -# use system libc/libm on Unix like targets +# use system libm on Unix like targets if("${TARGET_OS}" MATCHES "TIZENRT|NUTTX") - list(APPEND JERRY_LIBS jerry-libm) + list(APPEND JERRY_LIBS jerry-math) list(APPEND DEPS_LIB_JERRY_ARGS - -DJERRY_LIBC=OFF - -DJERRY_LIBM=ON - -DEXTERNAL_LIBC_INTERFACE=${EXTERNAL_LIBC_INTERFACE} + -DJERRY_MATH=ON -DEXTERNAL_CMAKE_SYSTEM_PROCESSOR=${EXTERNAL_CMAKE_SYSTEM_PROCESSOR} ) -elseif("${TARGET_OS}" MATCHES "LINUX|TIZEN|DARWIN") +elseif("${TARGET_OS}" MATCHES "LINUX|TIZEN|DARWIN|OPENWRT") list(APPEND JERRY_LIBS m) list(APPEND DEPS_LIB_JERRY_ARGS - -DJERRY_LIBC=OFF - -DJERRY_LIBM=OFF) + -DJERRY_MATH=OFF) +elseif("${TARGET_OS}" MATCHES "WINDOWS") + list(APPEND DEPS_LIB_JERRY_ARGS + -DJERRY_MATH=OFF) else() - list(APPEND JERRY_LIBS jerry-libm jerry-libc) + list(APPEND JERRY_LIBS jerry-math) list(APPEND DEPS_LIB_JERRY_ARGS - -DEXTERNAL_LIBC_INTERFACE=${EXTERNAL_LIBC_INTERFACE} + -DJERRY_MATH=ON -DEXTERNAL_CMAKE_SYSTEM_PROCESSOR=${EXTERNAL_CMAKE_SYSTEM_PROCESSOR} ) endif() # Add a few cmake options based on buildtype/external cmake defines if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - list(APPEND DEPS_LIB_JERRY_ARGS -DFEATURE_ERROR_MESSAGES=ON) + list(APPEND DEPS_LIB_JERRY_ARGS -DJERRY_ERROR_MESSAGES=ON) endif() # NuttX is not using the default port implementation of JerryScript -if("${TARGET_OS}" MATCHES "NUTTX") +if("${TARGET_OS}" MATCHES "NUTTX|TIZENRT") list(APPEND DEPS_LIB_JERRY_ARGS -DJERRY_PORT_DEFAULT=OFF) else() list(APPEND DEPS_LIB_JERRY_ARGS -DJERRY_PORT_DEFAULT=ON) endif() add_cmake_arg(DEPS_LIB_JERRY_ARGS ENABLE_LTO) -add_cmake_arg(DEPS_LIB_JERRY_ARGS FEATURE_MEM_STATS) -add_cmake_arg(DEPS_LIB_JERRY_ARGS FEATURE_ERROR_MESSAGES) -add_cmake_arg(DEPS_LIB_JERRY_ARGS FEATURE_DEBUGGER) -add_cmake_arg(DEPS_LIB_JERRY_ARGS FEATURE_DEBUGGER_PORT) -add_cmake_arg(DEPS_LIB_JERRY_ARGS MEM_HEAP_SIZE_KB) -add_cmake_arg(DEPS_LIB_JERRY_ARGS JERRY_HEAP_SECTION_ATTR) +add_cmake_arg(DEPS_LIB_JERRY_ARGS JERRY_MEM_STATS) +add_cmake_arg(DEPS_LIB_JERRY_ARGS JERRY_ERROR_MESSAGES) +add_cmake_arg(DEPS_LIB_JERRY_ARGS JERRY_DEBUGGER) +add_cmake_arg(DEPS_LIB_JERRY_ARGS JERRY_GLOBAL_HEAP_SIZE) +add_cmake_arg(DEPS_LIB_JERRY_ARGS JERRY_ATTR_GLOBAL_HEAP) separate_arguments(EXTRA_JERRY_CMAKE_PARAMS) + +build_lib_name(JERRY_CORE_NAME jerry-core) +build_lib_name(JERRY_LIBM_NAME jerry-math) +build_lib_name(JERRY_EXT_NAME jerry-ext) + set(DEPS_LIB_JERRY deps/jerry) set(DEPS_LIB_JERRY_SRC ${ROOT_DIR}/${DEPS_LIB_JERRY}) ExternalProject_Add(libjerry @@ -108,17 +130,21 @@ ExternalProject_Add(libjerry BINARY_DIR ${DEPS_LIB_JERRY} INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory - ${CMAKE_BINARY_DIR}/${DEPS_LIB_JERRY}/lib/ + ${CMAKE_BINARY_DIR}/${DEPS_LIB_JERRY}/lib/${CONFIG_TYPE} ${CMAKE_BINARY_DIR}/lib/ CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} -DCMAKE_BUILD_TYPE=${JERRY_CMAKE_BUILD_TYPE} -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} + -DENABLE_AMALGAM=ON -DJERRY_CMDLINE=OFF - -DJERRY_CMDLINE_MINIMAL=OFF - -DFEATURE_SNAPSHOT_EXEC=${ENABLE_SNAPSHOT} - -DFEATURE_SNAPSHOT_SAVE=OFF - -DFEATURE_PROFILE=${FEATURE_PROFILE} + -DJERRY_SNAPSHOT_EXEC=${ENABLE_SNAPSHOT} + -DJERRY_SNAPSHOT_SAVE=OFF + -DJERRY_PROFILE=${JERRY_PROFILE} + -DJERRY_LOGGING=ON + -DJERRY_LINE_INFO=${JERRY_LINE_INFO} + -DJERRY_VM_EXEC_STOP=ON + -DJERRY_ERROR_MESSAGES=ON -DENABLE_LTO=${ENABLE_LTO} ${DEPS_LIB_JERRY_ARGS} ${EXTRA_JERRY_CMAKE_PARAMS} @@ -126,42 +152,45 @@ ExternalProject_Add(libjerry set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES - ${CMAKE_BINARY_DIR}/lib/libjerry-core.a - ${CMAKE_BINARY_DIR}/lib/libjerry-libm.a - ${CMAKE_BINARY_DIR}/lib/libjerry-libc.a + ${CMAKE_BINARY_DIR}/lib/${JERRY_CORE_NAME} + ${CMAKE_BINARY_DIR}/lib/${JERRY_LIBM_NAME} + ${CMAKE_BINARY_DIR}/lib/${JERRY_EXT_NAME} ) # define external jerry-core target add_library(jerry-core STATIC IMPORTED) add_dependencies(jerry-core libjerry) set_property(TARGET jerry-core PROPERTY - IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/libjerry-core.a) - -# define external jerry-libc target -add_library(jerry-libc STATIC IMPORTED) -add_dependencies(jerry-libc libjerry) -set_property(TARGET jerry-libc PROPERTY - IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/libjerry-libc.a) + IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/${JERRY_CORE_NAME}) # define external jerry-libm target -add_library(jerry-libm STATIC IMPORTED) -add_dependencies(jerry-libm libjerry) -set_property(TARGET jerry-libm PROPERTY - IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/libjerry-libm.a) - -if(NOT "${TARGET_OS}" MATCHES "NUTTX") +add_library(jerry-math STATIC IMPORTED) +add_dependencies(jerry-math libjerry) +set_property(TARGET jerry-math PROPERTY + IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/${JERRY_LIBM_NAME}) + +# define external jerry-ext target +add_library(jerry-ext STATIC IMPORTED) +add_dependencies(jerry-ext libjerry) +set_property(TARGET jerry-ext PROPERTY + IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/${JERRY_EXT_NAME}) + +if(NOT "${TARGET_OS}" MATCHES "NUTTX|TIZENRT") + build_lib_name(JERRY_PORT_NAME jerry-port) + build_lib_name(JERRY_PORT_DEFAULT_NAME jerry-port-default) set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES - ${CMAKE_BINARY_DIR}/lib/libjerry-port.a + ${CMAKE_BINARY_DIR}/lib/${JERRY_PORT_NAME} ) # define external jerry-port-default target add_library(jerry-port-default STATIC IMPORTED) add_dependencies(jerry-port-default libjerry) set_property(TARGET jerry-port-default PROPERTY - IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/libjerry-port-default.a) + IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/${JERRY_PORT_DEFAULT_NAME}) set(JERRY_PORT_DIR ${DEPS_LIB_JERRY_SRC}/jerry-port/default) endif() -set(JERRY_INCLUDE_DIR ${DEPS_LIB_JERRY}/jerry-core/include) +set(JERRY_INCLUDE_DIR ${DEPS_LIB_JERRY_SRC}/jerry-core/include) +set(JERRY_EXT_DIR ${DEPS_LIB_JERRY_SRC}/jerry-ext) diff --git a/cmake/libtuv.cmake b/cmake/libtuv.cmake index 40eb22a94d..1c4ab4c9f3 100644 --- a/cmake/libtuv.cmake +++ b/cmake/libtuv.cmake @@ -18,6 +18,12 @@ cmake_minimum_required(VERSION 2.8) set(DEPS_TUV deps/libtuv) set(DEPS_TUV_SRC ${ROOT_DIR}/${DEPS_TUV}) +build_lib_name(LIBTUV_NAME tuv) +if("${TARGET_OS}" STREQUAL "MOCK") + string(TOLOWER ${TARGET_ARCH}-linux PLATFORM_DESCRIPTOR) +else() + string(TOLOWER ${TARGET_ARCH}-${TARGET_OS} PLATFORM_DESCRIPTOR) +endif() set(DEPS_TUV_TOOLCHAIN ${DEPS_TUV_SRC}/cmake/config/config_${PLATFORM_DESCRIPTOR}.cmake) message(STATUS "libtuv toolchain file: ${DEPS_TUV_TOOLCHAIN}") @@ -27,8 +33,8 @@ ExternalProject_Add(libtuv BUILD_IN_SOURCE 0 BINARY_DIR ${DEPS_TUV} INSTALL_COMMAND - ${CMAKE_COMMAND} -E copy - ${CMAKE_BINARY_DIR}/${DEPS_TUV}/lib/libtuv.a + ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_BINARY_DIR}/${DEPS_TUV}/lib/${CONFIG_TYPE}/ ${CMAKE_BINARY_DIR}/lib/ CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${DEPS_TUV_TOOLCHAIN} @@ -44,12 +50,21 @@ ExternalProject_Add(libtuv add_library(tuv STATIC IMPORTED) add_dependencies(tuv libtuv) set_property(TARGET tuv PROPERTY - IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/libtuv.a) + IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/${LIBTUV_NAME}) set_property(DIRECTORY APPEND PROPERTY - ADDITIONAL_MAKE_CLEAN_FILES ${CMAKE_BINARY_DIR}/lib/libtuv.a) + ADDITIONAL_MAKE_CLEAN_FILES ${CMAKE_BINARY_DIR}/lib/${LIBTUV_NAME}) set(TUV_INCLUDE_DIR ${DEPS_TUV_SRC}/include) set(TUV_LIBS tuv) -if("${TARGET_OS}" STREQUAL "LINUX") +if("${TARGET_OS}" STREQUAL "MOCK" OR + "${TARGET_OS}" STREQUAL "LINUX") list(APPEND TUV_LIBS pthread) +elseif("${TARGET_OS}" STREQUAL "WINDOWS") + list(APPEND TUV_LIBS + ws2_32.lib + UserEnv.lib + advapi32.lib + iphlpapi.lib + psapi.lib + shell32.lib) endif() diff --git a/cmake/mbedtls.cmake b/cmake/mbedtls.cmake new file mode 100644 index 0000000000..0a8e841e89 --- /dev/null +++ b/cmake/mbedtls.cmake @@ -0,0 +1,105 @@ +# 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. + +cmake_minimum_required(VERSION 2.8) + +set(MODULE_NAME "tls") + +if ("${TARGET_OS}" STREQUAL "TIZENRT") + set(MBEDTLS_LIBS "") + set(MBEDTLS_INCLUDE_DIR ${TARGET_SYSTEMROOT}/../external/include) +else() + set(DEPS_MBEDTLS deps/mbedtls) + set(DEPS_MBEDTLS_SRC ${ROOT_DIR}/${DEPS_MBEDTLS}) + set(DEPS_MBEDTLS_BUILD_DIR + ${CMAKE_BINARY_DIR}/${DEPS_MBEDTLS}/library/${CONFIG_TYPE}) + set(MODULE_BINARY_DIR ${DEPS_MBEDTLS_BUILD_DIR}) + + if("${TARGET_OS}" STREQUAL "TIZEN") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-cpp") + endif() + + if(USING_MSVC) + set(CONFIG_DELIMITER "") + else() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-sign-conversion") + set(CONFIG_DELIMITER "'") + endif() + + set(MBED_CONFIG "${CONFIG_DELIMITER}${CONFIG_DELIMITER}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${ROOT_DIR}/config/mbedtls") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMBEDTLS_CONFIG_FILE=${MBED_CONFIG}") + + # FIXME: + # Remove this workaround when the related bug is fixed in + # mbedtls. https://github.com/ARMmbed/mbedtls/issues/1550 + set(CMAKE_C_FLAGS_BCK "${CMAKE_C_FLAGS}") + string(REPLACE "-fsanitize=address" "" CMAKE_C_FLAGS ${CMAKE_C_FLAGS}) + + build_lib_name(MBED_X509_NAME mbedx509) + build_lib_name(MBED_TLS_NAME mbedtls) + build_lib_name(MBED_CRYPTO_NAME mbedcrypto) + ExternalProject_Add(mbedtls + PREFIX ${DEPS_MBEDTLS} + SOURCE_DIR ${DEPS_MBEDTLS_SRC} + BUILD_IN_SOURCE 0 + BINARY_DIR ${DEPS_MBEDTLS} + INSTALL_COMMAND + COMMAND ${CMAKE_COMMAND} -E copy + ${DEPS_MBEDTLS_BUILD_DIR}/${MBED_X509_NAME} ${ARCHIVE_DIR} + COMMAND ${CMAKE_COMMAND} -E copy + ${DEPS_MBEDTLS_BUILD_DIR}/${MBED_TLS_NAME} ${ARCHIVE_DIR} + COMMAND ${CMAKE_COMMAND} -E copy + ${DEPS_MBEDTLS_BUILD_DIR}/${MBED_CRYPTO_NAME} ${ARCHIVE_DIR} + CMAKE_ARGS + -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} + -DENABLE_PROGRAMS=OFF + -DENABLE_TESTING=OFF + ) + + # define external mbedtls target + add_library(libmbedtls STATIC IMPORTED) + add_dependencies(libmbedtls mbedtls) + set_property(TARGET libmbedtls PROPERTY + IMPORTED_LOCATION ${ARCHIVE_DIR}/${MBED_TLS_NAME}) + + # define external mbedx509 target + add_library(libmbedx509 STATIC IMPORTED) + add_dependencies(libmbedx509 mbedx509) + set_property(TARGET libmbedx509 PROPERTY + IMPORTED_LOCATION ${ARCHIVE_DIR}/${MBED_X509_NAME}) + + # define external libmbedcrypto target + add_library(libmbedcrypto STATIC IMPORTED) + add_dependencies(libmbedcrypto mbedcrypto) + set_property(TARGET libmbedcrypto PROPERTY + IMPORTED_LOCATION ${ARCHIVE_DIR}/${MBED_CRYPTO_NAME}) + + set_property(DIRECTORY APPEND PROPERTY + ADDITIONAL_MAKE_CLEAN_FILES + ${ARCHIVE_DIR}/${MBED_X509_NAME} + ${ARCHIVE_DIR}/${MBED_TLS_NAME} + ${ARCHIVE_DIR}/${MBED_CRYPTO_NAME} + ) + + set(MBEDTLS_LIBS libmbedtls libmbedx509 libmbedcrypto) + set(MBEDTLS_INCLUDE_DIR ${DEPS_MBEDTLS}/include) + + # FIXME: + # Remove this workaround when the related bug is fixed in + # mbedtls. https://github.com/ARMmbed/mbedtls/issues/1550 + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS_BCK}") +endif() diff --git a/config/mbedtls/config-for-iotjs.h b/config/mbedtls/config-for-iotjs.h new file mode 100644 index 0000000000..6581586bde --- /dev/null +++ b/config/mbedtls/config-for-iotjs.h @@ -0,0 +1,776 @@ +/* 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. + */ +/* + * Minimal configuration for TLS 1.1 (RFC 4346) + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_CONFIG_H +#define MBEDTLS_CONFIG_H + +/** + * \name SECTION: System support + * + * This section sets system specific settings. + * \{ + */ + +/** + * \def MBEDTLS_HAVE_ASM + * + * The compiler has support for asm(). + * + * Requires support for asm() in compiler. + * + * Used in: + * library/timing.c + * library/padlock.c + * include/mbedtls/bn_mul.h + * + * Comment to disable the use of assembly code. + */ +#define MBEDTLS_HAVE_ASM + +/** + * \def MBEDTLS_HAVE_TIME + * + * System has time.h and time(). + * The time does not need to be correct, only time differences are used, + * by contrast with MBEDTLS_HAVE_TIME_DATE + * + * Defining MBEDTLS_HAVE_TIME allows you to specify MBEDTLS_PLATFORM_TIME_ALT, + * MBEDTLS_PLATFORM_TIME_MACRO, MBEDTLS_PLATFORM_TIME_TYPE_MACRO and + * MBEDTLS_PLATFORM_STD_TIME. + * + * Comment if your system does not support time functions + */ +#define MBEDTLS_HAVE_TIME + +/** + * \def MBEDTLS_AES_ROM_TABLES + * + * Store the AES tables in ROM. + * + * Uncomment this macro to store the AES tables in ROM. + */ +#define MBEDTLS_AES_ROM_TABLES + +/** + * \def MBEDTLS_CIPHER_MODE_CBC + * + * Enable Cipher Block Chaining mode (CBC) for symmetric ciphers. + */ +#define MBEDTLS_CIPHER_MODE_CBC + +/** + * \def MBEDTLS_REMOVE_ARC4_CIPHERSUITES + * + * Remove RC4 ciphersuites by default in SSL / TLS. + * This flag removes the ciphersuites based on RC4 from the default list as + * returned by mbedtls_ssl_list_ciphersuites(). However, it is still possible to + * enable (some of) them with mbedtls_ssl_conf_ciphersuites() by including them + * explicitly. + * + * Uncomment this macro to remove RC4 ciphersuites by default. + */ +#define MBEDTLS_REMOVE_ARC4_CIPHERSUITES + +/** + * \def MBEDTLS_ECP_DP_SECP192R1_ENABLED + * + * MBEDTLS_ECP_XXXX_ENABLED: Enables specific curves within the Elliptic Curve + * module. By default all supported curves are enabled. + * + * Comment macros to disable the curve and functions for it + */ +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define MBEDTLS_ECP_DP_SECP384R1_ENABLED +#define MBEDTLS_ECP_DP_SECP256K1_ENABLED +#define MBEDTLS_ECP_DP_BP256R1_ENABLED +#define MBEDTLS_ECP_DP_BP384R1_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_RSA_ENABLED + * + * Enable the RSA-only based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED + * + * Enable the DHE-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_DHM_C, MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + * + * Enable the ECDHE-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + * + * Enable the ECDHE-ECDSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_ECDSA_C, MBEDTLS_X509_CRT_PARSE_C, + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED + * + * Enable the ECDH-ECDSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + */ +#define MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED + * + * Enable the ECDH-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + */ +#define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED + +/** + * \def MBEDTLS_PKCS1_V15 + * + * Enable support for PKCS#1 v1.5 encoding. + * + * Requires: MBEDTLS_RSA_C + * + * This enables support for PKCS#1 v1.5 operations. + */ +#define MBEDTLS_PKCS1_V15 + +/** + * \def MBEDTLS_PKCS1_V21 + * + * Enable support for PKCS#1 v2.1 encoding. + * + * Requires: MBEDTLS_MD_C, MBEDTLS_RSA_C + * + * This enables support for RSAES-OAEP and RSASSA-PSS operations. + */ +#define MBEDTLS_PKCS1_V21 + +/** + * \def MBEDTLS_SHA256_SMALLER + * + * Enable an implementation of SHA-256 that has lower ROM footprint but also + * lower performance. + * + * The default implementation is meant to be a reasonnable compromise between + * performance and size. This version optimizes more aggressively for size at + * the expense of performance. Eg on Cortex-M4 it reduces the size of + * mbedtls_sha256_process() from ~2KB to ~0.5KB for a performance hit of about + * 30%. + * + * Uncomment to enable the smaller implementation of SHA256. + */ +#define MBEDTLS_SHA256_SMALLER + +/** + * \def MBEDTLS_SSL_PROTO_TLS1 + * + * Enable support for TLS 1.0. + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for TLS 1.0 + */ +#define MBEDTLS_SSL_PROTO_TLS1 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1_1 + * + * Enable support for TLS 1.1 (and DTLS 1.0 if DTLS is enabled). + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for TLS 1.1 / DTLS 1.0 + */ +#define MBEDTLS_SSL_PROTO_TLS1_1 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1_2 + * + * Enable support for TLS 1.2 (and DTLS 1.2 if DTLS is enabled). + * + * Requires: MBEDTLS_SHA1_C or MBEDTLS_SHA256_C or MBEDTLS_SHA512_C + * (Depends on ciphersuites) + * + * Comment this macro to disable support for TLS 1.2 / DTLS 1.2 + */ +#define MBEDTLS_SSL_PROTO_TLS1_2 + +/** + * \def MBEDTLS_SSL_SERVER_NAME_INDICATION + * + * Enable support for RFC 6066 server name indication (SNI) in SSL. + * + * Requires: MBEDTLS_X509_CRT_PARSE_C + * + * Comment this macro to disable support for server name indication in SSL + */ +#define MBEDTLS_SSL_SERVER_NAME_INDICATION + +/* \} name SECTION: mbed TLS feature support */ + +/** + * \name SECTION: mbed TLS modules + * + * This section enables or disables entire modules in mbed TLS + * \{ + */ + +/** + * \def MBEDTLS_AES_C + * + * Enable the AES block cipher. + * + * Module: library/aes.c + * Caller: library/ssl_tls.c + * library/pem.c + * library/ctr_drbg.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA + * + * PEM_PARSE uses AES for decrypting encrypted keys. + */ +#define MBEDTLS_AES_C + +/** + * \def MBEDTLS_ASN1_PARSE_C + * + * Enable the generic ASN1 parser. + * + * Module: library/asn1.c + * Caller: library/x509.c + * library/dhm.c + * library/pkcs12.c + * library/pkcs5.c + * library/pkparse.c + */ +#define MBEDTLS_ASN1_PARSE_C + +/** + * \def MBEDTLS_ASN1_WRITE_C + * + * Enable the generic ASN1 writer. + * + * Module: library/asn1write.c + * Caller: library/ecdsa.c + * library/pkwrite.c + * library/x509_create.c + * library/x509write_crt.c + * library/mbedtls_x509write_csr.c + */ +#define MBEDTLS_ASN1_WRITE_C + +/** + * \def MBEDTLS_BASE64_C + * + * Enable the Base64 module. + * + * Module: library/base64.c + * Caller: library/pem.c + * + * This module is required for PEM support (required by X.509). + */ +#define MBEDTLS_BASE64_C + +/** + * \def MBEDTLS_BIGNUM_C + * + * Enable the multi-precision integer library. + * + * Module: library/bignum.c + * Caller: library/dhm.c + * library/ecp.c + * library/ecdsa.c + * library/rsa.c + * library/ssl_tls.c + * + * This module is required for RSA, DHM and ECC (ECDH, ECDSA) support. + */ +#define MBEDTLS_BIGNUM_C + +/** + * \def MBEDTLS_CIPHER_C + * + * Enable the generic cipher layer. + * + * Module: library/cipher.c + * Caller: library/ssl_tls.c + * + * Uncomment to enable generic cipher wrappers. + */ +#define MBEDTLS_CIPHER_C + +/** + * \def MBEDTLS_CTR_DRBG_C + * + * Enable the CTR_DRBG AES-256-based random generator. + * + * Module: library/ctr_drbg.c + * Caller: + * + * Requires: MBEDTLS_AES_C + * + * This module provides the CTR_DRBG AES-256 random number generator. + */ +#define MBEDTLS_CTR_DRBG_C + +/** + * \def MBEDTLS_DHM_C + * + * Enable the Diffie-Hellman-Merkle module. + * + * Module: library/dhm.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module is used by the following key exchanges: + * DHE-RSA, DHE-PSK + */ +#define MBEDTLS_DHM_C + +/** + * \def MBEDTLS_ECDH_C + * + * Enable the elliptic curve Diffie-Hellman library. + * + * Module: library/ecdh.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module is used by the following key exchanges: + * ECDHE-ECDSA, ECDHE-RSA, DHE-PSK + * + * Requires: MBEDTLS_ECP_C + */ +#define MBEDTLS_ECDH_C + +/** + * \def MBEDTLS_ECDSA_C + * + * Enable the elliptic curve DSA library. + * + * Module: library/ecdsa.c + * Caller: + * + * This module is used by the following key exchanges: + * ECDHE-ECDSA + * + * Requires: MBEDTLS_ECP_C, MBEDTLS_ASN1_WRITE_C, MBEDTLS_ASN1_PARSE_C + */ +#define MBEDTLS_ECDSA_C + +/** + * \def MBEDTLS_ECP_C + * + * Enable the elliptic curve over GF(p) library. + * + * Module: library/ecp.c + * Caller: library/ecdh.c + * library/ecdsa.c + * library/ecjpake.c + * + * Requires: MBEDTLS_BIGNUM_C and at least one MBEDTLS_ECP_DP_XXX_ENABLED + */ +#define MBEDTLS_ECP_C + +/** + * \def MBEDTLS_ENTROPY_C + * + * Enable the platform-specific entropy code. + * + * Module: library/entropy.c + * Caller: + * + * Requires: MBEDTLS_SHA512_C or MBEDTLS_SHA256_C + * + * This module provides a generic entropy pool + */ +#define MBEDTLS_ENTROPY_C + +/** + * \def MBEDTLS_GCM_C + * + * Enable the Galois/Counter Mode (GCM) for AES. + * + * Module: library/gcm.c + * + * Requires: MBEDTLS_AES_C or MBEDTLS_CAMELLIA_C + * + * This module enables the AES-GCM and CAMELLIA-GCM ciphersuites, if other + * requisites are enabled as well. + */ +#define MBEDTLS_GCM_C + +/** + * \def MBEDTLS_MD_C + * + * Enable the generic message digest layer. + * + * Module: library/mbedtls_md.c + * Caller: + * + * Uncomment to enable generic message digest wrappers. + */ +#define MBEDTLS_MD_C + +/** + * \def MBEDTLS_MD5_C + * + * Enable the MD5 hash algorithm. + * + * Module: library/mbedtls_md5.c + * Caller: library/mbedtls_md.c + * library/pem.c + * library/ssl_tls.c + * + * This module is required for SSL/TLS and X.509. + * PEM_PARSE uses MD5 for decrypting encrypted keys. + */ +#define MBEDTLS_MD5_C + +/** + * \def MBEDTLS_OID_C + * + * Enable the OID database. + * + * Module: library/oid.c + * Caller: library/asn1write.c + * library/pkcs5.c + * library/pkparse.c + * library/pkwrite.c + * library/rsa.c + * library/x509.c + * library/x509_create.c + * library/mbedtls_x509_crl.c + * library/mbedtls_x509_crt.c + * library/mbedtls_x509_csr.c + * library/x509write_crt.c + * library/mbedtls_x509write_csr.c + * + * This modules translates between OIDs and internal values. + */ +#define MBEDTLS_OID_C + +/** + * \def MBEDTLS_PEM_PARSE_C + * + * Enable PEM decoding / parsing. + * + * Module: library/pem.c + * Caller: library/dhm.c + * library/pkparse.c + * library/mbedtls_x509_crl.c + * library/mbedtls_x509_crt.c + * library/mbedtls_x509_csr.c + * + * Requires: MBEDTLS_BASE64_C + * + * This modules adds support for decoding / parsing PEM files. + */ +#define MBEDTLS_PEM_PARSE_C + +/** + * \def MBEDTLS_PK_C + * + * Enable the generic public (asymetric) key layer. + * + * Module: library/pk.c + * Caller: library/ssl_tls.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: MBEDTLS_RSA_C or MBEDTLS_ECP_C + * + * Uncomment to enable generic public key wrappers. + */ +#define MBEDTLS_PK_C + +/** + * \def MBEDTLS_PK_PARSE_C + * + * Enable the generic public (asymetric) key parser. + * + * Module: library/pkparse.c + * Caller: library/mbedtls_x509_crt.c + * library/mbedtls_x509_csr.c + * + * Requires: MBEDTLS_PK_C + * + * Uncomment to enable generic public key parse functions. + */ +#define MBEDTLS_PK_PARSE_C + +/** + * \def MBEDTLS_RSA_C + * + * Enable the RSA public-key cryptosystem. + * + * Module: library/rsa.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509.c + * + * This module is used by the following key exchanges: + * RSA, DHE-RSA, ECDHE-RSA, RSA-PSK + * + * Requires: MBEDTLS_BIGNUM_C, MBEDTLS_OID_C + */ +#define MBEDTLS_RSA_C + +/** + * \def MBEDTLS_SHA1_C + * + * Enable the SHA1 cryptographic hash algorithm. + * + * Module: library/mbedtls_sha1.c + * Caller: library/mbedtls_md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509write_crt.c + * + * This module is required for SSL/TLS and SHA1-signed certificates. + */ +#define MBEDTLS_SHA1_C + +/** + * \def MBEDTLS_SHA256_C + * + * Enable the SHA-224 and SHA-256 cryptographic hash algorithms. + * + * Module: library/mbedtls_sha256.c + * Caller: library/entropy.c + * library/mbedtls_md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * This module adds support for SHA-224 and SHA-256. + * This module is required for the SSL/TLS 1.2 PRF function. + */ +#define MBEDTLS_SHA256_C + +/** + * \def MBEDTLS_SSL_CLI_C + * + * Enable the SSL/TLS client code. + * + * Module: library/ssl_cli.c + * Caller: + * + * Requires: MBEDTLS_SSL_TLS_C + * + * This module is required for SSL/TLS client support. + */ +#define MBEDTLS_SSL_CLI_C + +/** + * \def MBEDTLS_SSL_SRV_C + * + * Enable the SSL/TLS server code. + * + * Module: library/ssl_srv.c + * Caller: + * + * Requires: MBEDTLS_SSL_TLS_C + * + * This module is required for SSL/TLS server support. + */ +#define MBEDTLS_SSL_SRV_C + +/** + * \def MBEDTLS_SSL_TLS_C + * + * Enable the generic SSL/TLS code. + * + * Module: library/ssl_tls.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: MBEDTLS_CIPHER_C, MBEDTLS_MD_C + * and at least one of the MBEDTLS_SSL_PROTO_XXX defines + * + * This module is required for SSL/TLS. + */ +#define MBEDTLS_SSL_TLS_C + +/** + * \def MBEDTLS_X509_USE_C + * + * Enable X.509 core for using certificates. + * + * Module: library/x509.c + * Caller: library/mbedtls_x509_crl.c + * library/mbedtls_x509_crt.c + * library/mbedtls_x509_csr.c + * + * Requires: MBEDTLS_ASN1_PARSE_C, MBEDTLS_BIGNUM_C, MBEDTLS_OID_C, + * MBEDTLS_PK_PARSE_C + * + * This module is required for the X.509 parsing modules. + */ +#define MBEDTLS_X509_USE_C + +/** + * \def MBEDTLS_X509_CRT_PARSE_C + * + * Enable X.509 certificate parsing. + * + * Module: library/mbedtls_x509_crt.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * Requires: MBEDTLS_X509_USE_C + * + * This module is required for X.509 certificate parsing. + */ +#define MBEDTLS_X509_CRT_PARSE_C + +/* \} name SECTION: mbed TLS modules */ + +#endif /* MBEDTLS_CONFIG_H */ diff --git a/config/nuttx/stm32f4dis/app/Makefile b/config/nuttx/stm32f4dis/app/Makefile index cda803a320..a908dcaa7a 100644 --- a/config/nuttx/stm32f4dis/app/Makefile +++ b/config/nuttx/stm32f4dis/app/Makefile @@ -68,7 +68,7 @@ HEAPSIZE = $(CONFIG_IOTJS_HEAPSIZE) ASRCS = setjmp.S CSRCS = jerry_port.c MAINSRC = iotjs_main.c -LIBS = libhttpparser.a libiotjs.a libjerry-core.a libtuv.a libjerry-libm.a +LIBS = libhttpparser.a libiotjs.a libjerry-core.a libtuv.a libjerry-math.a libjerry-ext.a AOBJS = $(ASRCS:.S=$(OBJEXT)) COBJS = $(CSRCS:.c=$(OBJEXT)) @@ -88,12 +88,12 @@ ifneq ($(CONFIG_BUILD_KERNEL),y) endif ifeq ($(CONFIG_WINDOWS_NATIVE),y) - BIN = ..\..\libapps$(LIBEXT) + BIN = $(APPDIR)\libapps$(LIBEXT) else ifeq ($(WINTOOL),y) - BIN = ..\\..\\libapps$(LIBEXT) + BIN = $(APPDIR)\\libapps$(LIBEXT) else - BIN = ../../libapps$(LIBEXT) + BIN = $(APPDIR)/libapps$(LIBEXT) endif endif diff --git a/config/nuttx/stm32f4dis/app/jerry_port.c b/config/nuttx/stm32f4dis/app/jerry_port.c index 886f749bbd..dd82d73526 100644 --- a/config/nuttx/stm32f4dis/app/jerry_port.c +++ b/config/nuttx/stm32f4dis/app/jerry_port.c @@ -38,17 +38,14 @@ void jerry_port_log(jerry_log_level_t level, /**< log level */ } /* jerry_port_log */ /** - * Dummy function to get the time zone. - * - * @return true + * Dummy function to get local time zone adjustment, in milliseconds, + * for the given timestamp. */ -bool jerry_port_get_time_zone(jerry_time_zone_t *tz_p) { - /* We live in UTC. */ - tz_p->offset = 0; - tz_p->daylight_saving_time = 0; - - return true; -} /* jerry_port_get_time_zone */ +double jerry_port_get_local_time_zone_adjustment(double unix_ms, bool is_utc) { + (void)unix_ms; + (void)is_utc; + return 0.0; +} /* jerry_port_get_local_time_zone_adjustment */ /** * Dummy function to get the current time. @@ -66,3 +63,102 @@ double jerry_port_get_current_time(void) { void jerryx_port_handler_print_char(char c) { /**< the character to print */ printf("%c", c); } /* jerryx_port_handler_print_char */ + +/** + * Normalize a file path + * + * @return length of the path written to the output buffer + */ +size_t jerry_port_normalize_path( + const char *in_path_p, /**< input file path */ + char *out_buf_p, /**< output buffer */ + size_t out_buf_size, /**< size of output buffer */ + char *base_file_p) /**< base file path */ +{ + (void)base_file_p; + + size_t len = strlen(in_path_p); + if (len + 1 > out_buf_size) { + return 0; + } + + /* Return the original string. */ + strcpy(out_buf_p, in_path_p); + return len; +} /* jerry_port_normalize_path */ + +/** + * Get the module object of a native module. + * + * @return undefined + */ +jerry_value_t jerry_port_get_native_module( + jerry_value_t name) /**< module specifier */ +{ + (void)name; + return jerry_create_undefined(); +} /* jerry_port_get_native_module */ + +/** + * Determines the size of the given file. + * @return size of the file + */ +static size_t jerry_port_get_file_size(FILE *file_p) /**< opened file */ +{ + fseek(file_p, 0, SEEK_END); + long size = ftell(file_p); + fseek(file_p, 0, SEEK_SET); + + return (size_t)size; +} /* jerry_port_get_file_size */ + +/** + * Opens file with the given path and reads its source. + * @return the source of the file + */ +uint8_t *jerry_port_read_source(const char *file_name_p, /**< file name */ + size_t *out_size_p) /**< [out] read bytes */ +{ + FILE *file_p = fopen(file_name_p, "rb"); + + if (file_p == NULL) { + jerry_port_log(JERRY_LOG_LEVEL_ERROR, "Error: failed to open file: %s\n", + file_name_p); + return NULL; + } + + size_t file_size = jerry_port_get_file_size(file_p); + uint8_t *buffer_p = (uint8_t *)malloc(file_size); + + if (buffer_p == NULL) { + fclose(file_p); + + jerry_port_log(JERRY_LOG_LEVEL_ERROR, + "Error: failed to allocate memory for module"); + return NULL; + } + + size_t bytes_read = fread(buffer_p, 1u, file_size, file_p); + + if (!bytes_read) { + fclose(file_p); + free(buffer_p); + + jerry_port_log(JERRY_LOG_LEVEL_ERROR, "Error: failed to read file: %s\n", + file_name_p); + return NULL; + } + + fclose(file_p); + *out_size_p = bytes_read; + + return buffer_p; +} /* jerry_port_read_source */ + +/** + * Release the previously opened file's content. + */ +void jerry_port_release_source(uint8_t *buffer_p) /**< buffer to free */ +{ + free(buffer_p); +} /* jerry_port_release_source */ diff --git a/config/nuttx/stm32f4dis/config.alloptions b/config/nuttx/stm32f4dis/config.alloptions new file mode 100644 index 0000000000..e57462bfd3 --- /dev/null +++ b/config/nuttx/stm32f4dis/config.alloptions @@ -0,0 +1,1608 @@ +# +# Automatically generated file; DO NOT EDIT. +# Nuttx/ Configuration +# + +# +# Build Setup +# +# CONFIG_EXPERIMENTAL is not set +# CONFIG_DEFAULT_SMALL is not set +CONFIG_HOST_LINUX=y +# CONFIG_HOST_OSX is not set +# CONFIG_HOST_WINDOWS is not set +# CONFIG_HOST_OTHER is not set + +# +# Build Configuration +# +CONFIG_APPS_DIR="../apps" +CONFIG_BUILD_FLAT=y +# CONFIG_BUILD_2PASS is not set + +# +# Binary Output Formats +# +# CONFIG_RRLOAD_BINARY is not set +CONFIG_INTELHEX_BINARY=y +# CONFIG_MOTOROLA_SREC is not set +CONFIG_RAW_BINARY=y +# CONFIG_UBOOT_UIMAGE is not set + +# +# Customize Header Files +# +# CONFIG_ARCH_STDINT_H is not set +# CONFIG_ARCH_STDBOOL_H is not set +# CONFIG_ARCH_MATH_H is not set +# CONFIG_ARCH_FLOAT_H is not set +# CONFIG_ARCH_STDARG_H is not set +# CONFIG_ARCH_DEBUG_H is not set + +# +# Debug Options +# +CONFIG_DEBUG_ALERT=y +# CONFIG_DEBUG_FEATURES is not set +CONFIG_ARCH_HAVE_STACKCHECK=y +# CONFIG_STACK_COLORATION is not set +CONFIG_ARCH_HAVE_HEAPCHECK=y +# CONFIG_HEAP_COLORATION is not set +# CONFIG_DEBUG_SYMBOLS is not set +CONFIG_ARCH_HAVE_CUSTOMOPT=y +# CONFIG_DEBUG_NOOPT is not set +# CONFIG_DEBUG_CUSTOMOPT is not set +CONFIG_DEBUG_FULLOPT=y + +# +# System Type +# +CONFIG_ARCH_ARM=y +# CONFIG_ARCH_AVR is not set +# CONFIG_ARCH_HC is not set +# CONFIG_ARCH_MIPS is not set +# CONFIG_ARCH_MISOC is not set +# CONFIG_ARCH_RENESAS is not set +# CONFIG_ARCH_RISCV is not set +# CONFIG_ARCH_SIM is not set +# CONFIG_ARCH_X86 is not set +# CONFIG_ARCH_XTENSA is not set +# CONFIG_ARCH_Z16 is not set +# CONFIG_ARCH_Z80 is not set +CONFIG_ARCH="arm" + +# +# ARM Options +# +# CONFIG_ARCH_CHIP_A1X is not set +# CONFIG_ARCH_CHIP_C5471 is not set +# CONFIG_ARCH_CHIP_DM320 is not set +# CONFIG_ARCH_CHIP_EFM32 is not set +# CONFIG_ARCH_CHIP_IMX1 is not set +# CONFIG_ARCH_CHIP_IMX6 is not set +# CONFIG_ARCH_CHIP_KINETIS is not set +# CONFIG_ARCH_CHIP_KL is not set +# CONFIG_ARCH_CHIP_LM is not set +# CONFIG_ARCH_CHIP_TIVA is not set +# CONFIG_ARCH_CHIP_LPC11XX is not set +# CONFIG_ARCH_CHIP_LPC17XX is not set +# CONFIG_ARCH_CHIP_LPC214X is not set +# CONFIG_ARCH_CHIP_LPC2378 is not set +# CONFIG_ARCH_CHIP_LPC31XX is not set +# CONFIG_ARCH_CHIP_LPC43XX is not set +# CONFIG_ARCH_CHIP_NUC1XX is not set +# CONFIG_ARCH_CHIP_SAMA5 is not set +# CONFIG_ARCH_CHIP_SAMD is not set +# CONFIG_ARCH_CHIP_SAML is not set +# CONFIG_ARCH_CHIP_SAM34 is not set +# CONFIG_ARCH_CHIP_SAMV7 is not set +CONFIG_ARCH_CHIP_STM32=y +# CONFIG_ARCH_CHIP_STM32F7 is not set +# CONFIG_ARCH_CHIP_STM32L4 is not set +# CONFIG_ARCH_CHIP_STR71X is not set +# CONFIG_ARCH_CHIP_TMS570 is not set +# CONFIG_ARCH_CHIP_MOXART is not set +# CONFIG_ARCH_ARM7TDMI is not set +# CONFIG_ARCH_ARM926EJS is not set +# CONFIG_ARCH_ARM920T is not set +# CONFIG_ARCH_CORTEXM0 is not set +# CONFIG_ARCH_CORTEXM3 is not set +CONFIG_ARCH_CORTEXM4=y +# CONFIG_ARCH_CORTEXM7 is not set +# CONFIG_ARCH_CORTEXA5 is not set +# CONFIG_ARCH_CORTEXA8 is not set +# CONFIG_ARCH_CORTEXA9 is not set +# CONFIG_ARCH_CORTEXR4 is not set +# CONFIG_ARCH_CORTEXR4F is not set +# CONFIG_ARCH_CORTEXR5 is not set +# CONFIG_ARCH_CORTEX5F is not set +# CONFIG_ARCH_CORTEXR7 is not set +# CONFIG_ARCH_CORTEXR7F is not set +CONFIG_ARCH_FAMILY="armv7-m" +CONFIG_ARCH_CHIP="stm32" +# CONFIG_ARM_TOOLCHAIN_IAR is not set +CONFIG_ARM_TOOLCHAIN_GNU=y +# CONFIG_ARMV7M_USEBASEPRI is not set +CONFIG_ARCH_HAVE_CMNVECTOR=y +# CONFIG_ARMV7M_CMNVECTOR is not set +# CONFIG_ARMV7M_LAZYFPU is not set +CONFIG_ARCH_HAVE_FPU=y +# CONFIG_ARCH_HAVE_DPFPU is not set +CONFIG_ARCH_FPU=y +# CONFIG_ARCH_HAVE_TRUSTZONE is not set +CONFIG_ARM_HAVE_MPU_UNIFIED=y +# CONFIG_ARM_MPU is not set + +# +# ARMV7M Configuration Options +# +# CONFIG_ARMV7M_HAVE_ICACHE is not set +# CONFIG_ARMV7M_HAVE_DCACHE is not set +# CONFIG_ARMV7M_HAVE_ITCM is not set +# CONFIG_ARMV7M_HAVE_DTCM is not set +# CONFIG_ARMV7M_TOOLCHAIN_IARL is not set +# CONFIG_ARMV7M_TOOLCHAIN_BUILDROOT is not set +# CONFIG_ARMV7M_TOOLCHAIN_CODEREDL is not set +# CONFIG_ARMV7M_TOOLCHAIN_CODESOURCERYL is not set +CONFIG_ARMV7M_TOOLCHAIN_GNU_EABIL=y +CONFIG_ARMV7M_HAVE_STACKCHECK=y +# CONFIG_ARMV7M_STACKCHECK is not set +# CONFIG_ARMV7M_ITMSYSLOG is not set +# CONFIG_SERIAL_TERMIOS is not set +# CONFIG_SDIO_DMA is not set +# CONFIG_SDIO_WIDTH_D1_ONLY is not set + +# +# STM32 Configuration Options +# +# CONFIG_ARCH_CHIP_STM32L151C6 is not set +# CONFIG_ARCH_CHIP_STM32L151C8 is not set +# CONFIG_ARCH_CHIP_STM32L151CB is not set +# CONFIG_ARCH_CHIP_STM32L151R6 is not set +# CONFIG_ARCH_CHIP_STM32L151R8 is not set +# CONFIG_ARCH_CHIP_STM32L151RB is not set +# CONFIG_ARCH_CHIP_STM32L151V6 is not set +# CONFIG_ARCH_CHIP_STM32L151V8 is not set +# CONFIG_ARCH_CHIP_STM32L151VB is not set +# CONFIG_ARCH_CHIP_STM32L152C6 is not set +# CONFIG_ARCH_CHIP_STM32L152C8 is not set +# CONFIG_ARCH_CHIP_STM32L152CB is not set +# CONFIG_ARCH_CHIP_STM32L152R6 is not set +# CONFIG_ARCH_CHIP_STM32L152R8 is not set +# CONFIG_ARCH_CHIP_STM32L152RB is not set +# CONFIG_ARCH_CHIP_STM32L152V6 is not set +# CONFIG_ARCH_CHIP_STM32L152V8 is not set +# CONFIG_ARCH_CHIP_STM32L152VB is not set +# CONFIG_ARCH_CHIP_STM32L162ZD is not set +# CONFIG_ARCH_CHIP_STM32L162VE is not set +# CONFIG_ARCH_CHIP_STM32F100C8 is not set +# CONFIG_ARCH_CHIP_STM32F100CB is not set +# CONFIG_ARCH_CHIP_STM32F100R8 is not set +# CONFIG_ARCH_CHIP_STM32F100RB is not set +# CONFIG_ARCH_CHIP_STM32F100RC is not set +# CONFIG_ARCH_CHIP_STM32F100RD is not set +# CONFIG_ARCH_CHIP_STM32F100RE is not set +# CONFIG_ARCH_CHIP_STM32F100V8 is not set +# CONFIG_ARCH_CHIP_STM32F100VB is not set +# CONFIG_ARCH_CHIP_STM32F100VC is not set +# CONFIG_ARCH_CHIP_STM32F100VD is not set +# CONFIG_ARCH_CHIP_STM32F100VE is not set +# CONFIG_ARCH_CHIP_STM32F102CB is not set +# CONFIG_ARCH_CHIP_STM32F103T8 is not set +# CONFIG_ARCH_CHIP_STM32F103TB is not set +# CONFIG_ARCH_CHIP_STM32F103C4 is not set +# CONFIG_ARCH_CHIP_STM32F103C8 is not set +# CONFIG_ARCH_CHIP_STM32F103CB is not set +# CONFIG_ARCH_CHIP_STM32F103R8 is not set +# CONFIG_ARCH_CHIP_STM32F103RB is not set +# CONFIG_ARCH_CHIP_STM32F103RC is not set +# CONFIG_ARCH_CHIP_STM32F103RD is not set +# CONFIG_ARCH_CHIP_STM32F103RE is not set +# CONFIG_ARCH_CHIP_STM32F103RG is not set +# CONFIG_ARCH_CHIP_STM32F103V8 is not set +# CONFIG_ARCH_CHIP_STM32F103VB is not set +# CONFIG_ARCH_CHIP_STM32F103VC is not set +# CONFIG_ARCH_CHIP_STM32F103VE is not set +# CONFIG_ARCH_CHIP_STM32F103ZE is not set +# CONFIG_ARCH_CHIP_STM32F105VB is not set +# CONFIG_ARCH_CHIP_STM32F105RB is not set +# CONFIG_ARCH_CHIP_STM32F107VC is not set +# CONFIG_ARCH_CHIP_STM32F205RG is not set +# CONFIG_ARCH_CHIP_STM32F207IG is not set +# CONFIG_ARCH_CHIP_STM32F207ZE is not set +# CONFIG_ARCH_CHIP_STM32F302K6 is not set +# CONFIG_ARCH_CHIP_STM32F302K8 is not set +# CONFIG_ARCH_CHIP_STM32F302CB is not set +# CONFIG_ARCH_CHIP_STM32F302CC is not set +# CONFIG_ARCH_CHIP_STM32F302RB is not set +# CONFIG_ARCH_CHIP_STM32F302RC is not set +# CONFIG_ARCH_CHIP_STM32F302VB is not set +# CONFIG_ARCH_CHIP_STM32F302VC is not set +# CONFIG_ARCH_CHIP_STM32F303K6 is not set +# CONFIG_ARCH_CHIP_STM32F303K8 is not set +# CONFIG_ARCH_CHIP_STM32F303C6 is not set +# CONFIG_ARCH_CHIP_STM32F303C8 is not set +# CONFIG_ARCH_CHIP_STM32F303CB is not set +# CONFIG_ARCH_CHIP_STM32F303CC is not set +# CONFIG_ARCH_CHIP_STM32F303RB is not set +# CONFIG_ARCH_CHIP_STM32F303RC is not set +# CONFIG_ARCH_CHIP_STM32F303RD is not set +# CONFIG_ARCH_CHIP_STM32F303RE is not set +# CONFIG_ARCH_CHIP_STM32F303VB is not set +# CONFIG_ARCH_CHIP_STM32F303VC is not set +# CONFIG_ARCH_CHIP_STM32F372C8 is not set +# CONFIG_ARCH_CHIP_STM32F372R8 is not set +# CONFIG_ARCH_CHIP_STM32F372V8 is not set +# CONFIG_ARCH_CHIP_STM32F372CB is not set +# CONFIG_ARCH_CHIP_STM32F372RB is not set +# CONFIG_ARCH_CHIP_STM32F372VB is not set +# CONFIG_ARCH_CHIP_STM32F372CC is not set +# CONFIG_ARCH_CHIP_STM32F372RC is not set +# CONFIG_ARCH_CHIP_STM32F372VC is not set +# CONFIG_ARCH_CHIP_STM32F373C8 is not set +# CONFIG_ARCH_CHIP_STM32F373R8 is not set +# CONFIG_ARCH_CHIP_STM32F373V8 is not set +# CONFIG_ARCH_CHIP_STM32F373CB is not set +# CONFIG_ARCH_CHIP_STM32F373RB is not set +# CONFIG_ARCH_CHIP_STM32F373VB is not set +# CONFIG_ARCH_CHIP_STM32F373CC is not set +# CONFIG_ARCH_CHIP_STM32F373RC is not set +# CONFIG_ARCH_CHIP_STM32F373VC is not set +# CONFIG_ARCH_CHIP_STM32F401RE is not set +# CONFIG_ARCH_CHIP_STM32F411RE is not set +# CONFIG_ARCH_CHIP_STM32F411VE is not set +# CONFIG_ARCH_CHIP_STM32F405RG is not set +# CONFIG_ARCH_CHIP_STM32F405VG is not set +# CONFIG_ARCH_CHIP_STM32F405ZG is not set +# CONFIG_ARCH_CHIP_STM32F407VE is not set +CONFIG_ARCH_CHIP_STM32F407VG=y +# CONFIG_ARCH_CHIP_STM32F407ZE is not set +# CONFIG_ARCH_CHIP_STM32F407ZG is not set +# CONFIG_ARCH_CHIP_STM32F407IE is not set +# CONFIG_ARCH_CHIP_STM32F407IG is not set +# CONFIG_ARCH_CHIP_STM32F427V is not set +# CONFIG_ARCH_CHIP_STM32F427Z is not set +# CONFIG_ARCH_CHIP_STM32F427I is not set +# CONFIG_ARCH_CHIP_STM32F429V is not set +# CONFIG_ARCH_CHIP_STM32F429Z is not set +# CONFIG_ARCH_CHIP_STM32F429I is not set +# CONFIG_ARCH_CHIP_STM32F429B is not set +# CONFIG_ARCH_CHIP_STM32F429N is not set +# CONFIG_ARCH_CHIP_STM32F446M is not set +# CONFIG_ARCH_CHIP_STM32F446R is not set +# CONFIG_ARCH_CHIP_STM32F446V is not set +# CONFIG_ARCH_CHIP_STM32F446Z is not set +# CONFIG_ARCH_CHIP_STM32F469A is not set +# CONFIG_ARCH_CHIP_STM32F469I is not set +# CONFIG_ARCH_CHIP_STM32F469B is not set +# CONFIG_ARCH_CHIP_STM32F469N is not set +CONFIG_STM32_FLASH_CONFIG_DEFAULT=y +# CONFIG_STM32_FLASH_CONFIG_4 is not set +# CONFIG_STM32_FLASH_CONFIG_6 is not set +# CONFIG_STM32_FLASH_CONFIG_8 is not set +# CONFIG_STM32_FLASH_CONFIG_B is not set +# CONFIG_STM32_FLASH_CONFIG_C is not set +# CONFIG_STM32_FLASH_CONFIG_D is not set +# CONFIG_STM32_FLASH_CONFIG_E is not set +# CONFIG_STM32_FLASH_CONFIG_F is not set +# CONFIG_STM32_FLASH_CONFIG_G is not set +# CONFIG_STM32_FLASH_CONFIG_I is not set +# CONFIG_STM32_STM32L15XX is not set +# CONFIG_STM32_ENERGYLITE is not set +# CONFIG_STM32_STM32F10XX is not set +# CONFIG_STM32_VALUELINE is not set +# CONFIG_STM32_CONNECTIVITYLINE is not set +# CONFIG_STM32_PERFORMANCELINE is not set +# CONFIG_STM32_USBACCESSLINE is not set +# CONFIG_STM32_HIGHDENSITY is not set +# CONFIG_STM32_MEDIUMDENSITY is not set +# CONFIG_STM32_LOWDENSITY is not set +# CONFIG_STM32_STM32F20XX is not set +# CONFIG_STM32_STM32F205 is not set +# CONFIG_STM32_STM32F207 is not set +# CONFIG_STM32_STM32F30XX is not set +# CONFIG_STM32_STM32F302 is not set +# CONFIG_STM32_STM32F303 is not set +# CONFIG_STM32_STM32F37XX is not set +CONFIG_STM32_STM32F40XX=y +# CONFIG_STM32_STM32F401 is not set +# CONFIG_STM32_STM32F411 is not set +# CONFIG_STM32_STM32F405 is not set +CONFIG_STM32_STM32F407=y +# CONFIG_STM32_STM32F427 is not set +# CONFIG_STM32_STM32F429 is not set +# CONFIG_STM32_STM32F446 is not set +# CONFIG_STM32_STM32F469 is not set +# CONFIG_STM32_DFU is not set + +# +# STM32 Peripheral Support +# +CONFIG_STM32_HAVE_CCM=y +# CONFIG_STM32_HAVE_USBDEV is not set +CONFIG_STM32_HAVE_OTGFS=y +CONFIG_STM32_HAVE_FSMC=y +# CONFIG_STM32_HAVE_LTDC is not set +CONFIG_STM32_HAVE_USART3=y +CONFIG_STM32_HAVE_UART4=y +CONFIG_STM32_HAVE_UART5=y +CONFIG_STM32_HAVE_USART6=y +# CONFIG_STM32_HAVE_UART7 is not set +# CONFIG_STM32_HAVE_UART8 is not set +CONFIG_STM32_HAVE_TIM1=y +CONFIG_STM32_HAVE_TIM2=y +CONFIG_STM32_HAVE_TIM3=y +CONFIG_STM32_HAVE_TIM4=y +CONFIG_STM32_HAVE_TIM5=y +CONFIG_STM32_HAVE_TIM6=y +CONFIG_STM32_HAVE_TIM7=y +CONFIG_STM32_HAVE_TIM8=y +CONFIG_STM32_HAVE_TIM9=y +CONFIG_STM32_HAVE_TIM10=y +CONFIG_STM32_HAVE_TIM11=y +CONFIG_STM32_HAVE_TIM12=y +CONFIG_STM32_HAVE_TIM13=y +CONFIG_STM32_HAVE_TIM14=y +# CONFIG_STM32_HAVE_TIM15 is not set +# CONFIG_STM32_HAVE_TIM16 is not set +# CONFIG_STM32_HAVE_TIM17 is not set +CONFIG_STM32_HAVE_ADC2=y +CONFIG_STM32_HAVE_ADC3=y +# CONFIG_STM32_HAVE_ADC4 is not set +# CONFIG_STM32_HAVE_ADC1_DMA is not set +# CONFIG_STM32_HAVE_ADC2_DMA is not set +# CONFIG_STM32_HAVE_ADC3_DMA is not set +# CONFIG_STM32_HAVE_ADC4_DMA is not set +# CONFIG_STM32_HAVE_SDADC1 is not set +# CONFIG_STM32_HAVE_SDADC2 is not set +# CONFIG_STM32_HAVE_SDADC3 is not set +# CONFIG_STM32_HAVE_SDADC1_DMA is not set +# CONFIG_STM32_HAVE_SDADC2_DMA is not set +# CONFIG_STM32_HAVE_SDADC3_DMA is not set +CONFIG_STM32_HAVE_CAN1=y +CONFIG_STM32_HAVE_CAN2=y +CONFIG_STM32_HAVE_DAC1=y +CONFIG_STM32_HAVE_DAC2=y +CONFIG_STM32_HAVE_RNG=y +CONFIG_STM32_HAVE_ETHMAC=y +CONFIG_STM32_HAVE_I2C2=y +CONFIG_STM32_HAVE_I2C3=y +CONFIG_STM32_HAVE_SPI2=y +CONFIG_STM32_HAVE_SPI3=y +# CONFIG_STM32_HAVE_SPI4 is not set +# CONFIG_STM32_HAVE_SPI5 is not set +# CONFIG_STM32_HAVE_SPI6 is not set +# CONFIG_STM32_HAVE_SAIPLL is not set +# CONFIG_STM32_HAVE_I2SPLL is not set +CONFIG_STM32_ADC1=y +# CONFIG_STM32_ADC2 is not set +# CONFIG_STM32_ADC3 is not set +# CONFIG_STM32_BKPSRAM is not set +# CONFIG_STM32_CAN1 is not set +# CONFIG_STM32_CAN2 is not set +# CONFIG_STM32_CCMDATARAM is not set +# CONFIG_STM32_CRC is not set +# CONFIG_STM32_CRYP is not set +# CONFIG_STM32_DMA1 is not set +# CONFIG_STM32_DMA2 is not set +# CONFIG_STM32_DAC1 is not set +# CONFIG_STM32_DAC2 is not set +# CONFIG_STM32_DCMI is not set +CONFIG_STM32_ETHMAC=y +# CONFIG_STM32_FSMC is not set +# CONFIG_STM32_HASH is not set +CONFIG_STM32_I2C1=y +# CONFIG_STM32_I2C2 is not set +# CONFIG_STM32_I2C3 is not set +CONFIG_STM32_OTGFS=y +# CONFIG_STM32_OTGHS is not set +CONFIG_STM32_PWR=y +# CONFIG_STM32_RNG is not set +CONFIG_STM32_SDIO=y +CONFIG_STM32_SPI1=y +# CONFIG_STM32_SPI2 is not set +# CONFIG_STM32_SPI3 is not set +CONFIG_STM32_SYSCFG=y +CONFIG_STM32_TIM1=y +# CONFIG_STM32_TIM2 is not set +CONFIG_STM32_TIM3=y +# CONFIG_STM32_TIM4 is not set +# CONFIG_STM32_TIM5 is not set +# CONFIG_STM32_TIM6 is not set +# CONFIG_STM32_TIM7 is not set +# CONFIG_STM32_TIM8 is not set +# CONFIG_STM32_TIM9 is not set +# CONFIG_STM32_TIM10 is not set +# CONFIG_STM32_TIM11 is not set +# CONFIG_STM32_TIM12 is not set +# CONFIG_STM32_TIM13 is not set +# CONFIG_STM32_TIM14 is not set +# CONFIG_STM32_USART1 is not set +# CONFIG_STM32_USART2 is not set +# CONFIG_STM32_USART3 is not set +# CONFIG_STM32_UART4 is not set +# CONFIG_STM32_UART5 is not set +CONFIG_STM32_USART6=y +# CONFIG_STM32_IWDG is not set +# CONFIG_STM32_WWDG is not set +CONFIG_STM32_ADC=y +CONFIG_STM32_SPI=y +CONFIG_STM32_I2C=y +# CONFIG_STM32_NOEXT_VECTORS is not set + +# +# Alternate Pin Mapping +# +# CONFIG_STM32_FLASH_PREFETCH is not set +# CONFIG_STM32_JTAG_DISABLE is not set +# CONFIG_STM32_JTAG_FULL_ENABLE is not set +# CONFIG_STM32_JTAG_NOJNTRST_ENABLE is not set +CONFIG_STM32_JTAG_SW_ENABLE=y +# CONFIG_STM32_DISABLE_IDLE_SLEEP_DURING_DEBUG is not set +# CONFIG_STM32_FORCEPOWER is not set +# CONFIG_ARCH_BOARD_STM32_CUSTOM_CLOCKCONFIG is not set +# CONFIG_STM32_CCMEXCLUDE is not set + +# +# Timer Configuration +# +# CONFIG_STM32_ONESHOT is not set +# CONFIG_STM32_FREERUN is not set +CONFIG_STM32_TIM1_PWM=y +CONFIG_STM32_TIM1_MODE=0 +CONFIG_STM32_TIM1_CHANNEL=1 +CONFIG_STM32_TIM1_CHMODE=0 +# CONFIG_STM32_TIM3_PWM is not set +# CONFIG_STM32_PWM_MULTICHAN is not set +# CONFIG_STM32_TIM1_ADC is not set +CONFIG_STM32_TIM3_ADC=y +CONFIG_STM32_TIM3_ADC1=y +CONFIG_HAVE_ADC1_TIMER=y +CONFIG_STM32_ADC1_SAMPLE_FREQUENCY=100 +CONFIG_STM32_ADC1_TIMTRIG=0 +# CONFIG_STM32_TIM1_CAP is not set +# CONFIG_STM32_TIM2_CAP is not set +# CONFIG_STM32_TIM3_CAP is not set +# CONFIG_STM32_TIM4_CAP is not set +# CONFIG_STM32_TIM5_CAP is not set +# CONFIG_STM32_TIM8_CAP is not set +# CONFIG_STM32_TIM9_CAP is not set +# CONFIG_STM32_TIM10_CAP is not set +# CONFIG_STM32_TIM11_CAP is not set +# CONFIG_STM32_TIM12_CAP is not set +# CONFIG_STM32_TIM13_CAP is not set +# CONFIG_STM32_TIM14_CAP is not set + +# +# ADC Configuration +# +CONFIG_STM32_USART=y +CONFIG_STM32_SERIALDRIVER=y + +# +# U[S]ART Configuration +# + +# +# U[S]ART Device Configuration +# +# CONFIG_STM32_USART2_SERIALDRIVER is not set +# CONFIG_STM32_USART2_1WIREDRIVER is not set +CONFIG_STM32_USART6_SERIALDRIVER=y +# CONFIG_STM32_USART6_1WIREDRIVER is not set +# CONFIG_USART6_RS485 is not set + +# +# Serial Driver Configuration +# +# CONFIG_SERIAL_DISABLE_REORDERING is not set +# CONFIG_STM32_FLOWCONTROL_BROKEN is not set +# CONFIG_STM32_USART_BREAKS is not set +# CONFIG_STM32_USART_SINGLEWIRE is not set + +# +# SPI Configuration +# +# CONFIG_STM32_SPI_INTERRUPTS is not set +# CONFIG_STM32_SPI_DMA is not set + +# +# I2C Configuration +# +# CONFIG_STM32_I2C_ALT is not set +# CONFIG_STM32_I2C_DYNTIMEO is not set +CONFIG_STM32_I2CTIMEOSEC=0 +CONFIG_STM32_I2CTIMEOMS=500 +CONFIG_STM32_I2CTIMEOTICKS=500 +# CONFIG_STM32_I2C_DUTY16_9 is not set + +# +# SDIO Configuration +# +CONFIG_SDIO_DMAPRIO=0x00010000 +# CONFIG_STM32_HAVE_RTC_COUNTER is not set +# CONFIG_STM32_HAVE_RTC_SUBSECONDS is not set + +# +# Ethernet MAC configuration +# +CONFIG_STM32_PHYADDR=0 +# CONFIG_STM32_PHYINIT is not set +# CONFIG_STM32_MII is not set +CONFIG_STM32_AUTONEG=y +CONFIG_STM32_PHYSR=31 +CONFIG_STM32_PHYSR_ALTCONFIG=y +CONFIG_STM32_PHYSR_ALTMODE=0x001c +CONFIG_STM32_PHYSR_10HD=0x0004 +CONFIG_STM32_PHYSR_100HD=0x0008 +CONFIG_STM32_PHYSR_10FD=0x0014 +CONFIG_STM32_PHYSR_100FD=0x0018 +# CONFIG_STM32_ETH_PTP is not set +CONFIG_STM32_RMII=y +# CONFIG_STM32_RMII_MCO1 is not set +# CONFIG_STM32_RMII_MCO2 is not set +CONFIG_STM32_RMII_EXTCLK=y +CONFIG_STM32_ETHMAC_HPWORK=y + +# +# USB FS Host Configuration +# + +# +# USB HS Host Configuration +# + +# +# USB Host Debug Configuration +# + +# +# USB Device Configuration +# + +# +# Architecture Options +# +# CONFIG_ARCH_NOINTC is not set +# CONFIG_ARCH_VECNOTIRQ is not set +# CONFIG_ARCH_DMA is not set +CONFIG_ARCH_HAVE_IRQPRIO=y +# CONFIG_ARCH_L2CACHE is not set +# CONFIG_ARCH_HAVE_COHERENT_DCACHE is not set +# CONFIG_ARCH_HAVE_ADDRENV is not set +# CONFIG_ARCH_NEED_ADDRENV_MAPPING is not set +# CONFIG_ARCH_HAVE_MULTICPU is not set +CONFIG_ARCH_HAVE_VFORK=y +# CONFIG_ARCH_HAVE_MMU is not set +CONFIG_ARCH_HAVE_MPU=y +# CONFIG_ARCH_NAND_HWECC is not set +# CONFIG_ARCH_HAVE_EXTCLK is not set +# CONFIG_ARCH_HAVE_POWEROFF is not set +CONFIG_ARCH_HAVE_RESET=y +# CONFIG_ARCH_USE_MPU is not set +# CONFIG_ARCH_IRQPRIO is not set +CONFIG_ARCH_STACKDUMP=y +# CONFIG_ENDIAN_BIG is not set +# CONFIG_ARCH_IDLE_CUSTOM is not set +# CONFIG_ARCH_HAVE_RAMFUNCS is not set +CONFIG_ARCH_HAVE_RAMVECTORS=y +# CONFIG_ARCH_RAMVECTORS is not set + +# +# Board Settings +# +CONFIG_BOARD_LOOPSPERMSEC=16717 +# CONFIG_ARCH_CALIBRATION is not set + +# +# Interrupt options +# +CONFIG_ARCH_HAVE_INTERRUPTSTACK=y +CONFIG_ARCH_INTERRUPTSTACK=0 +CONFIG_ARCH_HAVE_HIPRI_INTERRUPT=y +# CONFIG_ARCH_HIPRI_INTERRUPT is not set + +# +# Boot options +# +# CONFIG_BOOT_RUNFROMEXTSRAM is not set +CONFIG_BOOT_RUNFROMFLASH=y +# CONFIG_BOOT_RUNFROMISRAM is not set +# CONFIG_BOOT_RUNFROMSDRAM is not set +# CONFIG_BOOT_COPYTORAM is not set + +# +# Boot Memory Configuration +# +CONFIG_RAM_START=0x20000000 +CONFIG_RAM_SIZE=114688 +# CONFIG_ARCH_HAVE_SDRAM is not set + +# +# Board Selection +# +CONFIG_ARCH_BOARD_STM32F4_DISCOVERY=y +# CONFIG_ARCH_BOARD_MIKROE_STM32F4 is not set +# CONFIG_ARCH_BOARD_CUSTOM is not set +CONFIG_ARCH_BOARD="stm32f4discovery" + +# +# Common Board Options +# +CONFIG_ARCH_HAVE_LEDS=y +CONFIG_ARCH_LEDS=y +CONFIG_ARCH_HAVE_BUTTONS=y +CONFIG_ARCH_BUTTONS=y +CONFIG_ARCH_HAVE_IRQBUTTONS=y +# CONFIG_ARCH_IRQBUTTONS is not set + +# +# Board-Specific Options +# +CONFIG_STM32F4DISBB=y +# CONFIG_BOARD_CRASHDUMP is not set +CONFIG_LIB_BOARDCTL=y +# CONFIG_BOARDCTL_RESET is not set +# CONFIG_BOARDCTL_UNIQUEID is not set +CONFIG_BOARDCTL_USBDEVCTRL=y +# CONFIG_BOARDCTL_TSCTEST is not set +# CONFIG_BOARDCTL_GRAPHICS is not set +# CONFIG_BOARDCTL_IOCTL is not set + +# +# RTOS Features +# +CONFIG_DISABLE_OS_API=y +# CONFIG_DISABLE_POSIX_TIMERS is not set +# CONFIG_DISABLE_PTHREAD is not set +# CONFIG_DISABLE_SIGNALS is not set +# CONFIG_DISABLE_MQUEUE is not set +# CONFIG_DISABLE_ENVIRON is not set + +# +# Clocks and Timers +# +CONFIG_ARCH_HAVE_TICKLESS=y +# CONFIG_SCHED_TICKLESS is not set +CONFIG_USEC_PER_TICK=10000 +# CONFIG_SYSTEM_TIME64 is not set +CONFIG_CLOCK_MONOTONIC=y +CONFIG_ARCH_HAVE_TIMEKEEPING=y +# CONFIG_JULIAN_TIME is not set +CONFIG_START_YEAR=2013 +CONFIG_START_MONTH=1 +CONFIG_START_DAY=27 +CONFIG_MAX_WDOGPARMS=2 +CONFIG_PREALLOC_WDOGS=8 +CONFIG_WDOG_INTRESERVE=1 +CONFIG_PREALLOC_TIMERS=4 + +# +# Tasks and Scheduling +# +# CONFIG_SPINLOCK is not set +# CONFIG_INIT_NONE is not set +CONFIG_INIT_ENTRYPOINT=y +# CONFIG_INIT_FILEPATH is not set +CONFIG_USER_ENTRYPOINT="nsh_main" +CONFIG_RR_INTERVAL=200 +# CONFIG_SCHED_SPORADIC is not set +CONFIG_TASK_NAME_SIZE=31 +CONFIG_MAX_TASKS=16 +# CONFIG_SCHED_HAVE_PARENT is not set +CONFIG_SCHED_WAITPID=y + +# +# Pthread Options +# +CONFIG_MUTEX_TYPES=y +CONFIG_NPTHREAD_KEYS=4 +# CONFIG_PTHREAD_CLEANUP is not set +# CONFIG_CANCELLATION_POINTS is not set + +# +# Performance Monitoring +# +# CONFIG_SCHED_CPULOAD is not set +# CONFIG_SCHED_INSTRUMENTATION is not set + +# +# Files and I/O +# +CONFIG_DEV_CONSOLE=y +# CONFIG_FDCLONE_DISABLE is not set +# CONFIG_FDCLONE_STDIO is not set +CONFIG_SDCLONE_DISABLE=y +CONFIG_NFILE_DESCRIPTORS=8 +CONFIG_NFILE_STREAMS=8 +CONFIG_NAME_MAX=32 +# CONFIG_PRIORITY_INHERITANCE is not set + +# +# RTOS hooks +# +# CONFIG_BOARD_INITIALIZE is not set +# CONFIG_SCHED_STARTHOOK is not set +# CONFIG_SCHED_ATEXIT is not set +# CONFIG_SCHED_ONEXIT is not set +# CONFIG_SIG_EVTHREAD is not set + +# +# Signal Numbers +# +CONFIG_SIG_SIGUSR1=1 +CONFIG_SIG_SIGUSR2=2 +CONFIG_SIG_SIGALARM=3 +CONFIG_SIG_SIGCONDTIMEDOUT=16 +CONFIG_SIG_SIGWORK=17 + +# +# POSIX Message Queue Options +# +CONFIG_PREALLOC_MQ_MSGS=4 +CONFIG_MQ_MAXMSGSIZE=32 +# CONFIG_MODULE is not set + +# +# Work queue support +# +CONFIG_SCHED_WORKQUEUE=y +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_HPWORKPRIORITY=224 +CONFIG_SCHED_HPWORKPERIOD=50000 +CONFIG_SCHED_HPWORKSTACKSIZE=2048 +# CONFIG_SCHED_LPWORK is not set + +# +# Stack and heap information +# +CONFIG_IDLETHREAD_STACKSIZE=2048 +CONFIG_USERMAIN_STACKSIZE=2048 +CONFIG_PTHREAD_STACK_MIN=256 +CONFIG_PTHREAD_STACK_DEFAULT=2048 +# CONFIG_LIB_SYSCALL is not set + +# +# Device Drivers +# +# CONFIG_DISABLE_POLL is not set +CONFIG_DEV_NULL=y +# CONFIG_DEV_ZERO is not set +# CONFIG_DEV_URANDOM is not set +# CONFIG_DEV_LOOP is not set + +# +# Buffering +# +# CONFIG_DRVR_WRITEBUFFER is not set +# CONFIG_DRVR_READAHEAD is not set +# CONFIG_RAMDISK is not set +# CONFIG_CAN is not set +CONFIG_ARCH_HAVE_PWM_PULSECOUNT=y +# CONFIG_ARCH_HAVE_PWM_MULTICHAN is not set +CONFIG_PWM=y +# CONFIG_PWM_PULSECOUNT is not set +CONFIG_ARCH_HAVE_I2CRESET=y +CONFIG_I2C=y +# CONFIG_I2C_SLAVE is not set +# CONFIG_I2C_POLLED is not set +# CONFIG_I2C_RESET is not set +# CONFIG_I2C_TRACE is not set +# CONFIG_I2C_DRIVER is not set +CONFIG_SPI=y +# CONFIG_ARCH_HAVE_SPI_CRCGENERATION is not set +# CONFIG_ARCH_HAVE_SPI_CS_CONTROL is not set +CONFIG_ARCH_HAVE_SPI_BITORDER=y +# CONFIG_SPI_SLAVE is not set +CONFIG_SPI_EXCHANGE=y +# CONFIG_SPI_CMDDATA is not set +# CONFIG_SPI_CALLBACK is not set +# CONFIG_SPI_HWFEATURES is not set +# CONFIG_SPI_BITORDER is not set +# CONFIG_SPI_CS_DELAY_CONTROL is not set +# CONFIG_SPI_DRIVER is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_I2S is not set + +# +# Timer Driver Support +# +# CONFIG_TIMER is not set +# CONFIG_ONESHOT is not set +# CONFIG_RTC is not set +# CONFIG_WATCHDOG is not set +# CONFIG_TIMERS_CS2100CP is not set +CONFIG_ANALOG=y +CONFIG_ADC=y +CONFIG_ADC_FIFOSIZE=8 +# CONFIG_ADC_NO_STARTUP_CONV is not set +# CONFIG_ADC_ADS1242 is not set +# CONFIG_ADC_ADS125X is not set +# CONFIG_ADC_PGA11X is not set +# CONFIG_DAC is not set +# CONFIG_AUDIO_DEVICES is not set +# CONFIG_VIDEO_DEVICES is not set +# CONFIG_BCH is not set +# CONFIG_INPUT is not set + +# +# IO Expander/GPIO Support +# +# CONFIG_IOEXPANDER is not set +# CONFIG_DEV_GPIO is not set + +# +# LCD Driver Support +# +# CONFIG_LCD is not set +# CONFIG_SLCD is not set + +# +# LED Support +# +# CONFIG_USERLED is not set +# CONFIG_RGBLED is not set +# CONFIG_PCA9635PW is not set +# CONFIG_NCP5623C is not set +CONFIG_MMCSD=y +CONFIG_MMCSD_NSLOTS=1 +# CONFIG_MMCSD_READONLY is not set +# CONFIG_MMCSD_MULTIBLOCK_DISABLE is not set +CONFIG_MMCSD_MMCSUPPORT=y +CONFIG_MMCSD_HAVECARDDETECT=y +CONFIG_MMCSD_SPI=y +CONFIG_MMCSD_SPICLOCK=20000000 +CONFIG_MMCSD_SPIMODE=0 +CONFIG_ARCH_HAVE_SDIO=y +CONFIG_ARCH_HAVE_SDIOWAIT_WRCOMPLETE=y +CONFIG_MMCSD_SDIO=y +CONFIG_SDIO_PREFLIGHT=y +# CONFIG_SDIO_MUXBUS is not set +# CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE is not set +# CONFIG_SDIO_BLOCKSETUP is not set +# CONFIG_MODEM is not set +# CONFIG_MTD is not set +# CONFIG_EEPROM is not set +CONFIG_NETDEVICES=y + +# +# General Ethernet MAC Driver Options +# +CONFIG_NETDEV_LOOPBACK=y +CONFIG_LOOPBACK_HPWORK=y +# CONFIG_NETDEV_TELNET is not set +CONFIG_NETDEV_MULTINIC=y +CONFIG_ARCH_HAVE_NETDEV_STATISTICS=y +CONFIG_NETDEV_LATEINIT=y + +# +# External Ethernet MAC Device Support +# +# CONFIG_NET_DM90x0 is not set +# CONFIG_ENC28J60 is not set +# CONFIG_ENCX24J600 is not set +# CONFIG_NET_SLIP is not set +# CONFIG_NET_FTMAC100 is not set + +# +# External Ethernet PHY Device Support +# +# CONFIG_ARCH_PHY_INTERRUPT is not set +# CONFIG_ETH0_PHY_NONE is not set +# CONFIG_ETH0_PHY_AM79C874 is not set +# CONFIG_ETH0_PHY_KS8721 is not set +# CONFIG_ETH0_PHY_KSZ8041 is not set +# CONFIG_ETH0_PHY_KSZ8051 is not set +# CONFIG_ETH0_PHY_KSZ8061 is not set +# CONFIG_ETH0_PHY_KSZ8081 is not set +# CONFIG_ETH0_PHY_KSZ90x1 is not set +# CONFIG_ETH0_PHY_DP83848C is not set +CONFIG_ETH0_PHY_LAN8720=y +# CONFIG_ETH0_PHY_LAN8740 is not set +# CONFIG_ETH0_PHY_LAN8740A is not set +# CONFIG_ETH0_PHY_LAN8742A is not set +# CONFIG_ETH0_PHY_DM9161 is not set +CONFIG_ETH1_PHY_NONE=y +# CONFIG_ETH1_PHY_AM79C874 is not set +# CONFIG_ETH1_PHY_KS8721 is not set +# CONFIG_ETH1_PHY_KSZ8041 is not set +# CONFIG_ETH1_PHY_KSZ8051 is not set +# CONFIG_ETH1_PHY_KSZ8081 is not set +# CONFIG_ETH1_PHY_KSZ90x1 is not set +# CONFIG_ETH1_PHY_DP83848C is not set +# CONFIG_ETH1_PHY_LAN8720 is not set +# CONFIG_ETH1_PHY_DM9161 is not set +CONFIG_PIPES=y +CONFIG_DEV_PIPE_MAXSIZE=1024 +CONFIG_DEV_PIPE_SIZE=1024 +CONFIG_DEV_FIFO_SIZE=1024 +# CONFIG_PM is not set +# CONFIG_POWER is not set +# CONFIG_SENSORS is not set +CONFIG_SERIAL=y +# CONFIG_DEV_LOWCONSOLE is not set +CONFIG_SERIAL_REMOVABLE=y +# CONFIG_SERIAL_CONSOLE is not set +# CONFIG_16550_UART is not set +# CONFIG_UART_SERIALDRIVER is not set +# CONFIG_UART0_SERIALDRIVER is not set +# CONFIG_UART1_SERIALDRIVER is not set +# CONFIG_UART2_SERIALDRIVER is not set +# CONFIG_UART3_SERIALDRIVER is not set +# CONFIG_UART4_SERIALDRIVER is not set +# CONFIG_UART5_SERIALDRIVER is not set +# CONFIG_UART6_SERIALDRIVER is not set +# CONFIG_UART7_SERIALDRIVER is not set +# CONFIG_UART8_SERIALDRIVER is not set +# CONFIG_SCI0_SERIALDRIVER is not set +# CONFIG_SCI1_SERIALDRIVER is not set +# CONFIG_USART0_SERIALDRIVER is not set +# CONFIG_USART1_SERIALDRIVER is not set +# CONFIG_USART2_SERIALDRIVER is not set +# CONFIG_USART3_SERIALDRIVER is not set +# CONFIG_USART4_SERIALDRIVER is not set +# CONFIG_USART5_SERIALDRIVER is not set +CONFIG_USART6_SERIALDRIVER=y +# CONFIG_USART7_SERIALDRIVER is not set +# CONFIG_USART8_SERIALDRIVER is not set +# CONFIG_OTHER_UART_SERIALDRIVER is not set +CONFIG_MCU_SERIAL=y +CONFIG_STANDARD_SERIAL=y +CONFIG_SERIAL_NPOLLWAITERS=2 +# CONFIG_SERIAL_IFLOWCONTROL is not set +# CONFIG_SERIAL_OFLOWCONTROL is not set +# CONFIG_SERIAL_DMA is not set +CONFIG_ARCH_HAVE_SERIAL_TERMIOS=y +# CONFIG_USART2_SERIAL_CONSOLE is not set +# CONFIG_USART6_SERIAL_CONSOLE is not set +# CONFIG_OTHER_SERIAL_CONSOLE is not set +CONFIG_NO_SERIAL_CONSOLE=y + +# +# USART6 Configuration +# +CONFIG_USART6_RXBUFSIZE=256 +CONFIG_USART6_TXBUFSIZE=256 +CONFIG_USART6_BAUD=115200 +CONFIG_USART6_BITS=8 +CONFIG_USART6_PARITY=0 +CONFIG_USART6_2STOP=0 +# CONFIG_USART6_IFLOWCONTROL is not set +# CONFIG_USART6_OFLOWCONTROL is not set +# CONFIG_USART6_DMA is not set +# CONFIG_PSEUDOTERM is not set +CONFIG_USBDEV=y + +# +# USB Device Controller Driver Options +# +# CONFIG_USBDEV_ISOCHRONOUS is not set +# CONFIG_USBDEV_DUALSPEED is not set +CONFIG_USBDEV_SELFPOWERED=y +# CONFIG_USBDEV_BUSPOWERED is not set +CONFIG_USBDEV_MAXPOWER=100 +# CONFIG_USBDEV_DMA is not set +# CONFIG_ARCH_USBDEV_STALLQUEUE is not set +# CONFIG_USBDEV_TRACE is not set + +# +# USB Device Class Driver Options +# +# CONFIG_USBDEV_COMPOSITE is not set +# CONFIG_PL2303 is not set +CONFIG_CDCACM=y +CONFIG_CDCACM_CONSOLE=y +CONFIG_CDCACM_EP0MAXPACKET=64 +CONFIG_CDCACM_EPINTIN=1 +CONFIG_CDCACM_EPINTIN_FSSIZE=64 +CONFIG_CDCACM_EPINTIN_HSSIZE=64 +CONFIG_CDCACM_EPBULKOUT=3 +CONFIG_CDCACM_EPBULKOUT_FSSIZE=64 +CONFIG_CDCACM_EPBULKOUT_HSSIZE=512 +CONFIG_CDCACM_EPBULKIN=2 +CONFIG_CDCACM_EPBULKIN_FSSIZE=64 +CONFIG_CDCACM_EPBULKIN_HSSIZE=512 +CONFIG_CDCACM_NRDREQS=4 +CONFIG_CDCACM_NWRREQS=4 +CONFIG_CDCACM_BULKIN_REQLEN=96 +CONFIG_CDCACM_RXBUFSIZE=256 +CONFIG_CDCACM_TXBUFSIZE=256 +CONFIG_CDCACM_VENDORID=0x0525 +CONFIG_CDCACM_PRODUCTID=0xa4a7 +CONFIG_CDCACM_VENDORSTR="NuttX" +CONFIG_CDCACM_PRODUCTSTR="CDC/ACM Serial" +# CONFIG_USBMSC is not set +# CONFIG_USBHOST is not set +# CONFIG_HAVE_USBTRACE is not set +# CONFIG_DRIVERS_WIRELESS is not set +# CONFIG_DRIVERS_CONTACTLESS is not set + +# +# System Logging +# +# CONFIG_ARCH_SYSLOG is not set +# CONFIG_RAMLOG is not set +# CONFIG_SYSLOG_INTBUFFER is not set +# CONFIG_SYSLOG_TIMESTAMP is not set +# CONFIG_SYSLOG_SERIAL_CONSOLE is not set +CONFIG_SYSLOG_CHAR=y +# CONFIG_SYSLOG_CONSOLE is not set +# CONFIG_SYSLOG_NONE is not set +# CONFIG_SYSLOG_FILE is not set +# CONFIG_CONSOLE_SYSLOG is not set +CONFIG_SYSLOG_CHAR_CRLF=y +CONFIG_SYSLOG_DEVPATH="/dev/ttyS0" +# CONFIG_SYSLOG_CHARDEV is not set + +# +# Networking Support +# +CONFIG_ARCH_HAVE_NET=y +CONFIG_ARCH_HAVE_PHY=y +CONFIG_NET=y +# CONFIG_NET_PROMISCUOUS is not set + +# +# Driver buffer configuration +# +CONFIG_NET_ETH_MTU=590 +CONFIG_NET_ETH_TCP_RECVWNDO=536 +CONFIG_NET_GUARDSIZE=2 + +# +# Data link support +# +CONFIG_NET_MULTILINK=y +CONFIG_NET_ETHERNET=y +CONFIG_NET_LOOPBACK=y +# CONFIG_NET_TUN is not set + +# +# Network Device Operations +# +# CONFIG_NETDEV_PHY_IOCTL is not set + +# +# Internet Protocol Selection +# +CONFIG_NET_IPv4=y +# CONFIG_NET_IPv6 is not set + +# +# Socket Support +# +CONFIG_NSOCKET_DESCRIPTORS=8 +CONFIG_NET_NACTIVESOCKETS=16 +CONFIG_NET_SOCKOPTS=y +# CONFIG_NET_SOLINGER is not set + +# +# Raw Socket Support +# +# CONFIG_NET_PKT is not set + +# +# Unix Domain Socket Support +# +CONFIG_NET_LOCAL=y +CONFIG_NET_LOCAL_STREAM=y +CONFIG_NET_LOCAL_DGRAM=y + +# +# TCP/IP Networking +# +CONFIG_NET_TCP=y +# CONFIG_NET_TCPURGDATA is not set +CONFIG_NET_TCP_CONNS=8 +CONFIG_NET_MAX_LISTENPORTS=20 +CONFIG_NET_TCP_READAHEAD=y +CONFIG_NET_TCP_WRITE_BUFFERS=y +CONFIG_NET_TCP_NWRBCHAINS=8 +CONFIG_NET_TCP_RECVDELAY=0 +CONFIG_NET_TCPBACKLOG=y +# CONFIG_NET_SENDFILE is not set + +# +# UDP Networking +# +CONFIG_NET_UDP=y +# CONFIG_NET_UDP_CHECKSUMS is not set +CONFIG_NET_UDP_CONNS=8 +# CONFIG_NET_BROADCAST is not set +# CONFIG_NET_RXAVAIL is not set +CONFIG_NET_UDP_READAHEAD=y + +# +# ICMP Networking Support +# +# CONFIG_NET_ICMP is not set + +# +# IGMPv2 Client Support +# +# CONFIG_NET_IGMP is not set + +# +# ARP Configuration +# +CONFIG_NET_ARP=y +CONFIG_NET_ARPTAB_SIZE=16 +CONFIG_NET_ARP_MAXAGE=120 +# CONFIG_NET_ARP_IPIN is not set +CONFIG_NET_ARP_SEND=y +CONFIG_ARP_SEND_MAXTRIES=5 +CONFIG_ARP_SEND_DELAYMSEC=20 + +# +# Network I/O Buffer Support +# +CONFIG_NET_IOB=y +CONFIG_IOB_NBUFFERS=36 +CONFIG_IOB_BUFSIZE=196 +CONFIG_IOB_NCHAINS=8 +CONFIG_IOB_THROTTLE=8 +# CONFIG_NET_ARCH_INCR32 is not set +# CONFIG_NET_ARCH_CHKSUM is not set +# CONFIG_NET_STATISTICS is not set + +# +# Routing Table Configuration +# +# CONFIG_NET_ROUTE is not set +CONFIG_NET_HOSTNAME="" + +# +# Crypto API +# +# CONFIG_CRYPTO is not set + +# +# File Systems +# + +# +# File system configuration +# +# CONFIG_DISABLE_MOUNTPOINT is not set +# CONFIG_FS_AUTOMOUNTER is not set +# CONFIG_DISABLE_PSEUDOFS_OPERATIONS is not set +CONFIG_FS_READABLE=y +CONFIG_FS_WRITABLE=y +# CONFIG_FS_NAMED_SEMAPHORES is not set +CONFIG_FS_MQUEUE_MPATH="/var/mqueue" +# CONFIG_FS_RAMMAP is not set +CONFIG_FS_FAT=y +CONFIG_FAT_LCNAMES=y +CONFIG_FAT_LFN=y +CONFIG_FAT_MAXFNAME=32 +# CONFIG_FS_FATTIME is not set +# CONFIG_FAT_FORCE_INDIRECT is not set +# CONFIG_FAT_DMAMEMORY is not set +# CONFIG_FAT_DIRECT_RETRY is not set +# CONFIG_NFS is not set +# CONFIG_FS_NXFFS is not set +CONFIG_FS_ROMFS=y +# CONFIG_FS_TMPFS is not set +# CONFIG_FS_SMARTFS is not set +# CONFIG_FS_BINFS is not set +CONFIG_FS_PROCFS=y +# CONFIG_FS_PROCFS_REGISTER is not set + +# +# Exclude individual procfs entries +# +# CONFIG_FS_PROCFS_EXCLUDE_PROCESS is not set +# CONFIG_FS_PROCFS_EXCLUDE_UPTIME is not set +# CONFIG_FS_PROCFS_EXCLUDE_MOUNTS is not set +# CONFIG_FS_PROCFS_EXCLUDE_NET is not set +# CONFIG_FS_UNIONFS is not set + +# +# Graphics Support +# +# CONFIG_NX is not set + +# +# Memory Management +# +# CONFIG_MM_SMALL is not set +CONFIG_MM_REGIONS=2 +# CONFIG_ARCH_HAVE_HEAP2 is not set +# CONFIG_GRAN is not set + +# +# Audio Support +# +# CONFIG_AUDIO is not set + +# +# Wireless Support +# + +# +# Binary Loader +# +# CONFIG_BINFMT_DISABLE is not set +# CONFIG_BINFMT_EXEPATH is not set +# CONFIG_NXFLAT is not set +# CONFIG_ELF is not set +CONFIG_BUILTIN=y +# CONFIG_PIC is not set +# CONFIG_SYMTAB_ORDEREDBYNAME is not set + +# +# Library Routines +# + +# +# Standard C Library Options +# +CONFIG_STDIO_BUFFER_SIZE=64 +CONFIG_STDIO_LINEBUFFER=y +CONFIG_NUNGET_CHARS=2 +CONFIG_LIB_HOMEDIR="/" +CONFIG_LIBM=y +# CONFIG_NOPRINTF_FIELDWIDTH is not set +# CONFIG_LIBC_FLOATINGPOINT is not set +CONFIG_LIBC_LONG_LONG=y +# CONFIG_LIBC_IOCTL_VARIADIC is not set +# CONFIG_LIBC_WCHAR is not set +# CONFIG_LIBC_LOCALE is not set +CONFIG_LIB_RAND_ORDER=1 +# CONFIG_EOL_IS_CR is not set +# CONFIG_EOL_IS_LF is not set +# CONFIG_EOL_IS_BOTH_CRLF is not set +CONFIG_EOL_IS_EITHER_CRLF=y +# CONFIG_LIBC_EXECFUNCS is not set +CONFIG_POSIX_SPAWN_PROXY_STACKSIZE=1024 +CONFIG_TASK_SPAWN_DEFAULT_STACKSIZE=2048 +# CONFIG_LIBC_STRERROR is not set +# CONFIG_LIBC_PERROR_STDOUT is not set +CONFIG_LIBC_TMPDIR="/tmp" +CONFIG_LIBC_MAX_TMPFILE=32 +CONFIG_ARCH_LOWPUTC=y +# CONFIG_LIBC_LOCALTIME is not set +# CONFIG_TIME_EXTENDED is not set +CONFIG_LIB_SENDFILE_BUFSIZE=512 +# CONFIG_ARCH_ROMGETC is not set +# CONFIG_ARCH_OPTIMIZED_FUNCTIONS is not set +CONFIG_ARCH_HAVE_TLS=y +# CONFIG_TLS is not set +# CONFIG_LIBC_IPv6_ADDRCONV is not set +CONFIG_LIBC_NETDB=y +# CONFIG_NETDB_HOSTFILE is not set +# CONFIG_NETDB_DNSCLIENT is not set + +# +# Non-standard Library Support +# +# CONFIG_LIB_CRC64_FAST is not set +# CONFIG_LIB_KBDCODEC is not set +# CONFIG_LIB_SLCDCODEC is not set +# CONFIG_LIB_HEX2BIN is not set + +# +# Basic CXX Support +# +# CONFIG_C99_BOOL8 is not set +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +# CONFIG_CXX_NEWLONG is not set + +# +# uClibc++ Standard C++ Library +# +# CONFIG_UCLIBCXX is not set + +# +# Application Configuration +# + +# +# NxWidgets/NxWM +# + +# +# Built-In Applications +# +CONFIG_BUILTIN_PROXY_STACKSIZE=1024 + +# +# CAN Utilities +# + +# +# Examples +# +# CONFIG_EXAMPLES_ADC is not set +# CONFIG_EXAMPLES_BRIDGE is not set +# CONFIG_EXAMPLES_BUTTONS is not set +# CONFIG_EXAMPLES_CCTYPE is not set +# CONFIG_EXAMPLES_CHAT is not set +# CONFIG_EXAMPLES_CONFIGDATA is not set +# CONFIG_EXAMPLES_CPUHOG is not set +# CONFIG_EXAMPLES_CXXTEST is not set +# CONFIG_EXAMPLES_DHCPD is not set +# CONFIG_EXAMPLES_DISCOVER is not set +# CONFIG_EXAMPLES_ELF is not set +# CONFIG_EXAMPLES_FSTEST is not set +# CONFIG_EXAMPLES_FTPC is not set +# CONFIG_EXAMPLES_FTPD is not set +# CONFIG_EXAMPLES_HELLO is not set +# CONFIG_EXAMPLES_HELLOXX is not set +# CONFIG_EXAMPLES_HIDKBD is not set +# CONFIG_EXAMPLES_IGMP is not set +# CONFIG_EXAMPLES_JSON is not set +# CONFIG_EXAMPLES_KEYPADTEST is not set +# CONFIG_EXAMPLES_MEDIA is not set +# CONFIG_EXAMPLES_MM is not set +# CONFIG_EXAMPLES_MODBUS is not set +# CONFIG_EXAMPLES_MOUNT is not set +# CONFIG_EXAMPLES_NETLOOP is not set +# CONFIG_EXAMPLES_NETTEST is not set +# CONFIG_EXAMPLES_NRF24L01TERM is not set +CONFIG_EXAMPLES_NSH=y +CONFIG_EXAMPLES_NSH_CXXINITIALIZE=y +# CONFIG_EXAMPLES_NULL is not set +# CONFIG_EXAMPLES_NX is not set +# CONFIG_EXAMPLES_NXFFS is not set +# CONFIG_EXAMPLES_NXHELLO is not set +# CONFIG_EXAMPLES_NXIMAGE is not set +# CONFIG_EXAMPLES_NXLINES is not set +# CONFIG_EXAMPLES_NXTERM is not set +# CONFIG_EXAMPLES_NXTEXT is not set +# CONFIG_EXAMPLES_OSTEST is not set +# CONFIG_EXAMPLES_PCA9635 is not set +# CONFIG_EXAMPLES_PIPE is not set +# CONFIG_EXAMPLES_POSIXSPAWN is not set +# CONFIG_EXAMPLES_PPPD is not set +# CONFIG_EXAMPLES_PWM is not set +# CONFIG_EXAMPLES_RFID_READUID is not set +# CONFIG_EXAMPLES_RGBLED is not set +# CONFIG_EXAMPLES_SENDMAIL is not set +# CONFIG_EXAMPLES_SERIALBLASTER is not set +# CONFIG_EXAMPLES_SERIALRX is not set +# CONFIG_EXAMPLES_SERLOOP is not set +# CONFIG_EXAMPLES_SLCD is not set +# CONFIG_EXAMPLES_SMART is not set +# CONFIG_EXAMPLES_SMART_TEST is not set +# CONFIG_EXAMPLES_SMP is not set +# CONFIG_EXAMPLES_TCPECHO is not set +# CONFIG_EXAMPLES_TELNETD is not set +# CONFIG_EXAMPLES_TIFF is not set +# CONFIG_EXAMPLES_TOUCHSCREEN is not set +# CONFIG_EXAMPLES_UDGRAM is not set +# CONFIG_EXAMPLES_UDP is not set +# CONFIG_EXAMPLES_UDPBLASTER is not set +# CONFIG_EXAMPLES_USBSERIAL is not set +# CONFIG_EXAMPLES_USBTERM is not set +# CONFIG_EXAMPLES_USTREAM is not set +# CONFIG_EXAMPLES_WATCHDOG is not set +# CONFIG_EXAMPLES_WEBSERVER is not set +# CONFIG_EXAMPLES_XMLRPC is not set + +# +# File System Utilities +# +# CONFIG_FSUTILS_INIFILE is not set +# CONFIG_FSUTILS_PASSWD is not set + +# +# GPS Utilities +# +# CONFIG_GPSUTILS_MINMEA_LIB is not set + +# +# Graphics Support +# +# CONFIG_TIFF is not set +# CONFIG_GRAPHICS_TRAVELER is not set + +# +# Interpreters +# +# CONFIG_INTERPRETERS_BAS is not set +# CONFIG_INTERPRETERS_FICL is not set +# CONFIG_INTERPRETERS_MICROPYTHON is not set +# CONFIG_INTERPRETERS_MINIBASIC is not set +# CONFIG_INTERPRETERS_PCODE is not set + +# +# FreeModBus +# +# CONFIG_MODBUS is not set + +# +# Network Utilities +# +# CONFIG_NETUTILS_CHAT is not set +# CONFIG_NETUTILS_CODECS is not set +# CONFIG_NETUTILS_DHCPD is not set +# CONFIG_NETUTILS_DISCOVER is not set +# CONFIG_NETUTILS_ESP8266 is not set +# CONFIG_NETUTILS_FTPC is not set +# CONFIG_NETUTILS_FTPD is not set +# CONFIG_NETUTILS_JSON is not set +CONFIG_NETUTILS_NETLIB=y +# CONFIG_NETUTILS_NTPCLIENT is not set +# CONFIG_NETUTILS_PPPD is not set +# CONFIG_NETUTILS_SMTP is not set +# CONFIG_NETUTILS_TELNETD is not set +# CONFIG_NETUTILS_TFTPC is not set +# CONFIG_NETUTILS_WEBCLIENT is not set +# CONFIG_NETUTILS_WEBSERVER is not set +# CONFIG_NETUTILS_XMLRPC is not set + +# +# NSH Library +# +CONFIG_NSH_LIBRARY=y +# CONFIG_NSH_MOTD is not set + +# +# Command Line Configuration +# +CONFIG_NSH_READLINE=y +# CONFIG_NSH_CLE is not set +CONFIG_NSH_LINELEN=128 +# CONFIG_NSH_DISABLE_SEMICOLON is not set +CONFIG_NSH_CMDPARMS=y +CONFIG_NSH_MAXARGUMENTS=6 +CONFIG_NSH_ARGCAT=y +CONFIG_NSH_NESTDEPTH=3 +# CONFIG_NSH_DISABLEBG is not set +CONFIG_NSH_BUILTIN_APPS=y + +# +# Disable Individual commands +# +# CONFIG_NSH_DISABLE_ADDROUTE is not set +# CONFIG_NSH_DISABLE_ARP is not set +# CONFIG_NSH_DISABLE_BASENAME is not set +# CONFIG_NSH_DISABLE_CAT is not set +# CONFIG_NSH_DISABLE_CD is not set +# CONFIG_NSH_DISABLE_CP is not set +# CONFIG_NSH_DISABLE_CMP is not set +CONFIG_NSH_DISABLE_DATE=y +# CONFIG_NSH_DISABLE_DD is not set +# CONFIG_NSH_DISABLE_DF is not set +# CONFIG_NSH_DISABLE_DELROUTE is not set +# CONFIG_NSH_DISABLE_DIRNAME is not set +# CONFIG_NSH_DISABLE_ECHO is not set +# CONFIG_NSH_DISABLE_EXEC is not set +# CONFIG_NSH_DISABLE_EXIT is not set +# CONFIG_NSH_DISABLE_FREE is not set +# CONFIG_NSH_DISABLE_GET is not set +# CONFIG_NSH_DISABLE_HELP is not set +# CONFIG_NSH_DISABLE_HEXDUMP is not set +# CONFIG_NSH_DISABLE_IFCONFIG is not set +# CONFIG_NSH_DISABLE_IFUPDOWN is not set +# CONFIG_NSH_DISABLE_KILL is not set +# CONFIG_NSH_DISABLE_LOSETUP is not set +CONFIG_NSH_DISABLE_LOSMART=y +# CONFIG_NSH_DISABLE_LS is not set +# CONFIG_NSH_DISABLE_MB is not set +# CONFIG_NSH_DISABLE_MKDIR is not set +# CONFIG_NSH_DISABLE_MKFATFS is not set +# CONFIG_NSH_DISABLE_MKFIFO is not set +# CONFIG_NSH_DISABLE_MKRD is not set +# CONFIG_NSH_DISABLE_MH is not set +# CONFIG_NSH_DISABLE_MOUNT is not set +# CONFIG_NSH_DISABLE_MV is not set +# CONFIG_NSH_DISABLE_MW is not set +CONFIG_NSH_DISABLE_PRINTF=y +# CONFIG_NSH_DISABLE_PS is not set +# CONFIG_NSH_DISABLE_PUT is not set +# CONFIG_NSH_DISABLE_PWD is not set +# CONFIG_NSH_DISABLE_RM is not set +# CONFIG_NSH_DISABLE_RMDIR is not set +# CONFIG_NSH_DISABLE_SET is not set +# CONFIG_NSH_DISABLE_SH is not set +# CONFIG_NSH_DISABLE_SLEEP is not set +# CONFIG_NSH_DISABLE_TIME is not set +# CONFIG_NSH_DISABLE_TEST is not set +# CONFIG_NSH_DISABLE_UMOUNT is not set +# CONFIG_NSH_DISABLE_UNAME is not set +# CONFIG_NSH_DISABLE_UNSET is not set +# CONFIG_NSH_DISABLE_USLEEP is not set +# CONFIG_NSH_DISABLE_WGET is not set +# CONFIG_NSH_DISABLE_XD is not set +CONFIG_NSH_MMCSDMINOR=0 +CONFIG_NSH_MMCSDSLOTNO=0 +CONFIG_NSH_MMCSDSPIPORTNO=0 + +# +# Configure Command Options +# +CONFIG_NSH_CMDOPT_DF_H=y +# CONFIG_NSH_CMDOPT_DD_STATS is not set +CONFIG_NSH_CODECS_BUFSIZE=128 +CONFIG_NSH_CMDOPT_HEXDUMP=y +CONFIG_NSH_PROC_MOUNTPOINT="/proc" +CONFIG_NSH_FILEIOSIZE=512 + +# +# Scripting Support +# +# CONFIG_NSH_DISABLESCRIPT is not set +# CONFIG_NSH_DISABLE_ITEF is not set +# CONFIG_NSH_DISABLE_LOOPS is not set +CONFIG_NSH_ROMFSETC=y +# CONFIG_NSH_ROMFSRC is not set +CONFIG_NSH_ROMFSMOUNTPT="/test" +CONFIG_NSH_INITSCRIPT="init.d/rcS" +CONFIG_NSH_ROMFSDEVNO=0 +CONFIG_NSH_ROMFSSECTSIZE=64 +CONFIG_NSH_DEFAULTROMFS=y +# CONFIG_NSH_ARCHROMFS is not set +# CONFIG_NSH_CUSTOMROMFS is not set +CONFIG_NSH_FATDEVNO=1 +CONFIG_NSH_FATSECTSIZE=512 +CONFIG_NSH_FATNSECTORS=1024 +CONFIG_NSH_FATMOUNTPT="/tmp" + +# +# Console Configuration +# +CONFIG_NSH_CONSOLE=y +# CONFIG_NSH_USBCONSOLE is not set +# CONFIG_NSH_ALTCONDEV is not set +CONFIG_NSH_ARCHINIT=y + +# +# Networking Configuration +# +CONFIG_NSH_NETINIT=y +# CONFIG_NSH_NETINIT_THREAD is not set + +# +# IP Address Configuration +# + +# +# IPv4 Addresses +# +CONFIG_NSH_IPADDR=0x0a000002 +CONFIG_NSH_DRIPADDR=0x0a000001 +CONFIG_NSH_NETMASK=0xffffff00 +# CONFIG_NSH_NOMAC is not set +CONFIG_NSH_MAX_ROUNDTRIP=20 +# CONFIG_NSH_LOGIN is not set +# CONFIG_NSH_CONSOLE_LOGIN is not set + +# +# Platform-specific Support +# +# CONFIG_PLATFORM_CONFIGDATA is not set + +# +# System Libraries and NSH Add-Ons +# +# CONFIG_SYSTEM_CDCACM is not set +# CONFIG_SYSTEM_CLE is not set +# CONFIG_SYSTEM_CUTERM is not set +# CONFIG_SYSTEM_FREE is not set +# CONFIG_SYSTEM_HEX2BIN is not set +# CONFIG_SYSTEM_HEXED is not set +# CONFIG_SYSTEM_I2CTOOL is not set +# CONFIG_SYSTEM_INSTALL is not set +CONFIG_IOTJS=y +CONFIG_IOTJS_PRIORITY=100 +CONFIG_IOTJS_STACKSIZE=16384 +# CONFIG_SYSTEM_NETDB is not set +# CONFIG_SYSTEM_RAMTEST is not set +CONFIG_READLINE_HAVE_EXTMATCH=y +CONFIG_SYSTEM_READLINE=y +CONFIG_READLINE_ECHO=y +CONFIG_READLINE_TABCOMPLETION=y +CONFIG_READLINE_MAX_BUILTINS=64 +CONFIG_READLINE_MAX_EXTCMDS=64 +CONFIG_READLINE_CMD_HISTORY=y +CONFIG_READLINE_CMD_HISTORY_LINELEN=80 +CONFIG_READLINE_CMD_HISTORY_LEN=16 +# CONFIG_SYSTEM_SUDOKU is not set +# CONFIG_SYSTEM_SYSTEM is not set +# CONFIG_SYSTEM_TEE is not set +# CONFIG_SYSTEM_UBLOXMODEM is not set +# CONFIG_SYSTEM_VI is not set +# CONFIG_SYSTEM_ZMODEM is not set diff --git a/config/nuttx/stm32f4dis/.config.default b/config/nuttx/stm32f4dis/config.default similarity index 100% rename from config/nuttx/stm32f4dis/.config.default rename to config/nuttx/stm32f4dis/config.default diff --git a/config/nuttx/stm32f4dis/.config.travis b/config/nuttx/stm32f4dis/config.travis similarity index 100% rename from config/nuttx/stm32f4dis/.config.travis rename to config/nuttx/stm32f4dis/config.travis diff --git a/config/nuttx/stm32f7nucleo/config.default b/config/nuttx/stm32f7nucleo/config.default new file mode 100644 index 0000000000..dd54ca16e9 --- /dev/null +++ b/config/nuttx/stm32f7nucleo/config.default @@ -0,0 +1,93 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="nucleo-144" +CONFIG_ARCH_BOARD_NUCLEO_144=y +CONFIG_ARCH_BUTTONS=y +CONFIG_ARCH_CHIP_STM32F767ZI=y +CONFIG_ARCH_CHIP_STM32F7=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARMV7M_DCACHE=y +CONFIG_ARMV7M_DCACHE_WRITETHROUGH=y +CONFIG_ARMV7M_DTCM=y +CONFIG_ARMV7M_ICACHE=y +CONFIG_BOARD_LOOPSPERMSEC=43103 +CONFIG_BUILTIN=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_ETH0_PHY_LAN8742A=y +CONFIG_FS_PROCFS=y +CONFIG_FS_PROCFS_REGISTER=y +CONFIG_FS_TMPFS=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_IOTJS=y +CONFIG_LIB_HOSTNAME="stntest" +CONFIG_MAX_TASKS=16 +CONFIG_MAX_WDOGPARMS=2 +CONFIG_MM_REGIONS=3 +CONFIG_NET=y +CONFIG_NETDB_DNSCLIENT=y +CONFIG_NETUTILS_DISCOVER=y +CONFIG_NETUTILS_WEBCLIENT=y +CONFIG_NET_ARP_IPIN=y +CONFIG_NET_ARP_SEND=y +CONFIG_NET_BROADCAST=y +CONFIG_NET_ETH_PKTSIZE=1500 +CONFIG_NET_ICMP=y +CONFIG_NET_ICMP_SOCKET=y +CONFIG_NET_IGMP=y +CONFIG_NET_LOCAL=y +CONFIG_NET_LOOPBACK=y +CONFIG_NET_ROUTE=y +CONFIG_NET_SOLINGER=y +CONFIG_NET_STATISTICS=y +CONFIG_NET_TCP=y +CONFIG_NET_TCPBACKLOG=y +CONFIG_NET_UDP=y +CONFIG_NET_UDP_CHECKSUMS=y +CONFIG_NFILE_DESCRIPTORS=8 +CONFIG_NFILE_STREAMS=8 +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_READLINE=y +CONFIG_NUCLEO_CONSOLE_VIRTUAL=y +CONFIG_PREALLOC_MQ_MSGS=4 +CONFIG_PREALLOC_TIMERS=4 +CONFIG_PREALLOC_WDOGS=4 +CONFIG_PTHREAD_MUTEX_TYPES=y +CONFIG_RAM_SIZE=245760 +CONFIG_RAM_START=0x20010000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=100 +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_LPWORKPRIORITY=176 +CONFIG_SCHED_WAITPID=y +CONFIG_SDCLONE_DISABLE=y +CONFIG_SPI=y +CONFIG_STACK_COLORATION=y +CONFIG_START_DAY=30 +CONFIG_START_MONTH=11 +CONFIG_START_YEAR=2015 +CONFIG_STM32F7_ETHMAC=y +CONFIG_STM32F7_PHYADDR=0 +CONFIG_STM32F7_PHYSR=31 +CONFIG_STM32F7_PHYSR_100FD=0x0018 +CONFIG_STM32F7_PHYSR_100HD=0x0008 +CONFIG_STM32F7_PHYSR_10FD=0x0014 +CONFIG_STM32F7_PHYSR_10HD=0x0004 +CONFIG_STM32F7_PHYSR_ALTCONFIG=y +CONFIG_STM32F7_PHYSR_ALTMODE=0x001c +CONFIG_SYSTEM_DHCPC_RENEW=y +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_PING=y +CONFIG_TASK_NAME_SIZE=0 +CONFIG_USART3_SERIAL_CONSOLE=y +CONFIG_USER_ENTRYPOINT="nsh_main" +CONFIG_WDOG_INTRESERVE=0 diff --git a/config/nuttx/stm32f7nucleo/nuttx.profile b/config/nuttx/stm32f7nucleo/nuttx.profile new file mode 100644 index 0000000000..1a53968dd0 --- /dev/null +++ b/config/nuttx/stm32f7nucleo/nuttx.profile @@ -0,0 +1,6 @@ +ENABLE_MODULE_IOTJS_BASIC_MODULES +ENABLE_MODULE_IOTJS_CORE_MODULES +ENABLE_MODULE_ADC +ENABLE_MODULE_GPIO +ENABLE_MODULE_PWM +ENABLE_MODULE_STM32F7NUCLEO diff --git a/config/tizen/.gbs.conf b/config/tizen/.gbs.conf new file mode 100644 index 0000000000..27429e20fe --- /dev/null +++ b/config/tizen/.gbs.conf @@ -0,0 +1,4 @@ +[general] +upstream_branch = ${upstreamversion} +upstream_tag = ${upstreamversion} +packaging_dir = config/tizen/packaging diff --git a/config/tizen/filter.txt b/config/tizen/filter.txt new file mode 100644 index 0000000000..c9fdf90895 --- /dev/null +++ b/config/tizen/filter.txt @@ -0,0 +1,2 @@ +P /.git +- .git diff --git a/config/tizen/gbsbuild.sh b/config/tizen/gbsbuild.sh new file mode 100755 index 0000000000..2232793afc --- /dev/null +++ b/config/tizen/gbsbuild.sh @@ -0,0 +1,92 @@ +#!/bin/bash + +# 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. + +function print_usage { + echo "USAGE: $0 [--debug|--clean]" + echo "" + echo "Optional arguments:" + echo "--debug: Build IoT.js in debug mode. The default is release mode." + echo "--clean: Make a clean gbs build by deleting the old build root." + echo "" +} + +buildtype="release" +unset cleanbuild + +while [ -n "$1" ]; do + case $1 in + --debug ) + buildtype="debug" + ;; + --clean ) + cleanbuild=true + ;; + * ) + print_usage + exit 1; + ;; + esac + shift +done + +echo "******************************************************************" +echo "* Tizen GBS build *" +echo "* ~/.gbs.conf sample is at 'config/tizen/sample.gbs.conf'. *" +echo "******************************************************************" +echo "" +echo "This working folder will be copied to ../iotjs_tizen_gbs" + +cd .. +echo copy from $OLDPWD to ../iotjs_tizen_gbs +cp -ra $OLDPWD iotjs_tizen_gbs +cd iotjs_tizen_gbs +echo -e "\n(1) Now, cloning submodules. " +git submodule init +echo -e "\n(2) Update submodules... " +git submodule update + +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(3) Calling core gbs build command" +gbsconf="config/tizen/sample.gbs.conf" +gbscommand="gbs -c $gbsconf build -A armv7l --include-all" +gbscommand+=" ${cleanbuild:+--clean} --define='build_mode $buildtype'" +gbscommand+=" --define='external_build_options $IOTJS_BUILD_OPTION'" + +ret=0 +echo $gbscommand +if eval $gbscommand +then + echo "========================================================" + echo "1. GBS Build is successful." + echo "2. You can find rpm packages in below folder" + echo " ~/GBS-ROOT/local/repos/tizen50m2/armv7l/RPMS" +else + echo "GBS Build failed!" + ret=1 +fi +cd .. +rm -rf iotjs_tizen_gbs +cd iotjs +exit $ret diff --git a/config/tizen/iotjs_tizen.patch b/config/tizen/iotjs_tizen.patch new file mode 100644 index 0000000000..7e163adf0e --- /dev/null +++ b/config/tizen/iotjs_tizen.patch @@ -0,0 +1,136 @@ +diff --git a/.gbs.conf b/.gbs.conf +new file mode 100644 +index 0000000..27429e2 +--- /dev/null ++++ b/.gbs.conf +@@ -0,0 +1,4 @@ ++[general] ++upstream_branch = ${upstreamversion} ++upstream_tag = ${upstreamversion} ++packaging_dir = config/tizen/packaging +diff --git a/LICENSE.BSD-3-Clause b/LICENSE.BSD-3-Clause +new file mode 100644 +index 0000000..d8fdf69 +--- /dev/null ++++ b/LICENSE.BSD-3-Clause +@@ -0,0 +1,30 @@ ++/* Copyright (c) 2013, Sony Mobile Communications AB ++ * Copyright (c) 2012, Google Inc. ++ All rights reserved. ++ ++ Redistribution and use in source and binary forms, with or without ++ modification, are permitted provided that the following conditions are ++ met: ++ ++ * Redistributions of source code must retain the above copyright ++ notice, this list of conditions and the following disclaimer. ++ * Redistributions in binary form must reproduce the above ++ copyright notice, this list of conditions and the following disclaimer ++ in the documentation and/or other materials provided with the ++ distribution. ++ * Neither the name of Google Inc. nor the names of its ++ contributors may be used to endorse or promote products derived from ++ this software without specific prior written permission. ++ ++ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++*/ +diff --git a/LICENSE.BSD-4-Clause b/LICENSE.BSD-4-Clause +new file mode 100644 +index 0000000..c48e617 +--- /dev/null ++++ b/LICENSE.BSD-4-Clause +@@ -0,0 +1,28 @@ ++Copyright (c) 1995, 1999 ++ Berkeley Software Design, Inc. All rights reserved. ++ ++Redistribution and use in source and binary forms, with or without ++modification, are permitted provided that the following conditions ++are met: ++1. Redistributions of source code must retain the above copyright ++ notice, this list of conditions and the following disclaimer. ++2. Redistributions in binary form must reproduce the above copyright ++ notice, this list of conditions and the following disclaimer in the ++ documentation and/or other materials provided with the distribution. ++3. All advertising materials mentioning features or use of this software ++ must display the following acknowledgement: ++ This product includes software developed by Berkeley Software Design, Inc. ++4. Neither the name of the University nor the names of its contributors ++ may be used to endorse or promote products derived from this software ++ without specific prior written permission. ++ ++THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR ++IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, ++INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +diff --git a/LICENSE.MIT b/LICENSE.MIT +new file mode 100644 +index 0000000..bf37ab9 +--- /dev/null ++++ b/LICENSE.MIT +@@ -0,0 +1,23 @@ ++The MIT License (MIT) ++Copyright (c) 2016 JerryScript Community ++Copyright (c) 2015 ++Copyright (c) 2015 Stefan Bellus ++Copyright (c) 2005-2014 RoadNarrows LLC. ++ ++Permission is hereby granted, free of charge, to any person obtaining a copy ++of this software and associated documentation files (the "Software"), to deal ++in the Software without restriction, including without limitation the rights ++to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++copies of the Software, and to permit persons to whom the Software is ++furnished to do so, subject to the following conditions: ++ ++The above copyright notice and this permission notice shall be included in all ++copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++SOFTWARE. +diff --git a/config/mbedtls/config-for-iotjs.h b/config/mbedtls/config-for-iotjs.h +index 6581586..745ebbf 100644 +--- a/config/mbedtls/config-for-iotjs.h ++++ b/config/mbedtls/config-for-iotjs.h +@@ -57,7 +57,9 @@ + * + * Comment to disable the use of assembly code. + */ ++#ifndef TIZEN_ASAN_BUILD + #define MBEDTLS_HAVE_ASM ++#endif + + /** + * \def MBEDTLS_HAVE_TIME +diff --git a/config/tizen/packaging/iotjs.spec b/config/tizen/packaging/iotjs.spec +index 5be21f0..d111e71 100644 +--- a/config/tizen/packaging/iotjs.spec ++++ b/config/tizen/packaging/iotjs.spec +@@ -3,7 +3,7 @@ Version: 1.0.0 + Release: 0 + Summary: Platform for Internet of Things with JavaScript + Group: Network & Connectivity +-License: Apache-2.0 ++License: Apache-2.0 and BSD-1.0 and BSD-3-Clause and MIT + URL: https://www.iotjs.net/ + Source: %{name}-%{version}.tar.gz + Source1: %{name}.pc.in diff --git a/config/tizen/packaging/iotjs.manifest b/config/tizen/packaging/iotjs.manifest new file mode 100644 index 0000000000..f5a44ec920 --- /dev/null +++ b/config/tizen/packaging/iotjs.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/config/tizen/packaging/iotjs.pc.in b/config/tizen/packaging/iotjs.pc.in new file mode 100644 index 0000000000..4860237209 --- /dev/null +++ b/config/tizen/packaging/iotjs.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: iotjs +Description: Platform for Internet of Things with JavaScript +Version: 1.0.0 +Libs: -L${libdir} -liotjs -lcapi-system-peripheral-io -lpthread -lcurl -ldlog -lappcore-agent +Cflags: -I${includedir}/iotjs diff --git a/config/tizen/packaging/iotjs.spec b/config/tizen/packaging/iotjs.spec new file mode 100644 index 0000000000..d122215cef --- /dev/null +++ b/config/tizen/packaging/iotjs.spec @@ -0,0 +1,124 @@ +Name: iotjs +Version: 1.0.0 +Release: 0 +Summary: Platform for Internet of Things with JavaScript +Group: Network & Connectivity +License: Apache-2.0 +URL: https://www.iotjs.net/ +Source: %{name}-%{version}.tar.gz +Source1: %{name}.pc.in +Source1001: %{name}.manifest +ExclusiveArch: %arm %ix86 x86_64 + +BuildRequires: python +BuildRequires: cmake +BuildRequires: glibc-static +#BuildRequires: aul +BuildRequires: pkgconfig(appcore-agent) +BuildRequires: pkgconfig(capi-appfw-service-application) +BuildRequires: pkgconfig(capi-appfw-app-common) +#BuildRequires: pkgconfig(capi-appfw-package-manager) +BuildRequires: pkgconfig(capi-appfw-application) +BuildRequires: pkgconfig(capi-system-peripheral-io) +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(capi-appfw-app-control) +BuildRequires: pkgconfig(bundle) +#BuildRequires: pkgconfig(st_things_sdkapi) + +Requires(postun): /sbin/ldconfig +Requires(post): /sbin/ldconfig + +%description +Platform for Internet of Things with JavaScript + +# Initialize the variables +%{!?build_mode: %define build_mode release} +%{!?external_build_options: %define external_build_options %{nil}} + +%package service +Summary: Development files for %{name} +Group: Network & Connectivity/Service +Requires: %{name} = %{version}-%{release} + +%description service +The %{name}-service package contains service iotjs files for +developing applications that use %{name}. + +%package devel +Summary: Header files for %{name} +Group: Network & Connectivity/Service +Requires: %{name} = %{version}-%{release} + +%description devel +Development libraries for %{name} + +%prep +%setup -q -c +chmod g-w %_sourcedir/* +cat LICENSE +cp %{SOURCE1001} . + +%build +V=1 VERBOSE=1 ./tools/build.py \ + --clean \ + --buildtype=%{build_mode} \ + --profile=test/profiles/tizen.profile \ + --jerry-profile $PWD/test/profiles/tizen-jerry.profile \ + --js-backtrace ON \ + --target-arch=noarch \ + --target-os=tizen \ +%ifarch %{arm} + --target-board=rpi3 \ +%endif + --external-lib=capi-system-peripheral-io \ + --external-lib=capi-appfw-app-common \ + --external-lib=dlog \ + --external-lib=bundle \ + --external-lib=capi-appfw-app-control \ + --external-lib=appcore-agent \ + --external-lib=pthread \ + --external-lib=glib-2.0 \ + --external-include-dir=/usr/include/dlog/ \ + --external-include-dir=/usr/include/appcore-agent/ \ + --external-include-dir=/usr/include/appfw/ \ + --compile-flag="%(pkg-config --cflags glib-2.0)" \ + --compile-flag=-D__TIZEN__ \ + --compile-flag=-DENABLE_DEBUG_LOG \ + --create-shared-lib \ + --no-init-submodule \ + --no-parallel-build \ + %{?asan:--compile-flag=-DTIZEN_ASAN_BUILD} \ + %{external_build_options} +# --external-lib=sdkapi \ + +%install +mkdir -p %{buildroot}%{_bindir} +mkdir -p %{buildroot}%{_includedir}/iotjs +mkdir -p %{buildroot}%{_libdir}/iotjs +mkdir -p %{buildroot}%{_libdir}/pkgconfig + + +cp ./build/noarch-tizen/%{build_mode}/bin/iotjs %{buildroot}%{_bindir}/ +cp ./build/noarch-tizen/%{build_mode}/lib/*.so %{buildroot}%{_libdir}/ + +cp ./src/platform/tizen/iotjs_tizen_service_app.h %{buildroot}%{_includedir}/iotjs +cp ./config/tizen/packaging/%{name}.pc.in %{buildroot}/%{_libdir}/pkgconfig/%{name}.pc + +%post -p /sbin/ldconfig +%postun -p /sbin/ldconfig + + +%files +%manifest config/tizen/packaging/%{name}.manifest +%defattr(-,root,root,-) +%{_libdir}/libiotjs.so +%license LICENSE +%{_bindir}/* + +%files devel +%manifest config/tizen/packaging/%{name}.manifest +%defattr(-,root,root,-) +%{_libdir}/libiotjs.so +%{_libdir}/pkgconfig/%{name}.pc +%{_includedir}/* diff --git a/config/tizen/patch4tizenorg.sh b/config/tizen/patch4tizenorg.sh new file mode 100755 index 0000000000..871c87d97e --- /dev/null +++ b/config/tizen/patch4tizenorg.sh @@ -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 . + diff --git a/config/tizen/release.sh b/config/tizen/release.sh new file mode 100755 index 0000000000..13b770fc87 --- /dev/null +++ b/config/tizen/release.sh @@ -0,0 +1,70 @@ +#!/bin/bash +ROOT=`pwd` + +# 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 release script *" +echo "******************************************************************" + +repo=$1 + +if [ "$repo" == "../iotjs_tizen" -o "$repo" == "../iotjs_tizen/" ]; then + echo "Syncing with: tizen iotjs" +else + echo "Usage: $0 [ ../iotjs_tizen ]" + exit 0 +fi + +if [ ! -d ../iotjs_tizen ]; then + # echo "cloning..." + echo "Error: $repo not exist" + exit 0 +fi + +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) Modify version... " +hash=`git log | head -1 | cut -f2 -d' ' | cut -c 1-7` +today=`date +%y%m%d` +sed -i "s/\(IOTJS_VERSION \".*\"\)/\1 \"$today\_$hash\"/g" src/iotjs_def.h + +echo -e "\n(4) Patch for tizen.org... " +patch -p1 < config/tizen/iotjs_tizen.patch +cp -ra config/tizen/packaging . + +merge_filter="merge config/tizen/filter.txt" +rsync -av --delete --delete-excluded --filter="$merge_filter" . $repo + +cd $repo + +git add -A +echo "=======================================" +echo git commit -m "IOTJS_Release_$today""_$hash" +echo "=======================================" +msg="IOTJS_Release_$today""_$hash" +git commit -m "$msg" +cd $ROOT + +rm -rf ../iotjs_tizen_org diff --git a/config/tizen/sample.gbs.conf b/config/tizen/sample.gbs.conf new file mode 100644 index 0000000000..7093daf38b --- /dev/null +++ b/config/tizen/sample.gbs.conf @@ -0,0 +1,83 @@ +[general] +#profile = profile.tizen40m3 +#profile = profile.tizen50 +#profile = profile.tizen50m1 +#profile = profile.tizen50m2 +profile = profile.tizen55m1 + +upstream_branch = ${upstreamversion} +upstream_tag = ${upstreamversion} +packaging_dir = config/tizen/packaging + + +[profile.tizen55m1] +obs = obs.spin +repos = repo.tizen55m1_base, repo.tizen55m1_standard + +[repo.tizen55m1_base] +url = http://download.tizen.org/releases/milestone/tizen/base/tizen-base_20190503.1/repos/standard/packages/ + +[repo.tizen55m1_standard] +url = http://download.tizen.org/releases/milestone/tizen/unified/tizen-unified_20190523.1/repos/standard/packages/ + + + +[profile.tizen50m2] +obs = obs.spin +repos = repo.tizen50m2_base, repo.tizen50m2_standard + +[repo.tizen50m2_base] +url = http://download.tizen.org/releases/milestone/tizen/base/tizen-base_20180928.1/repos/standard/packages/ + +[repo.tizen50m2_standard] +url = http://download.tizen.org/releases/milestone/tizen/unified/tizen-unified_20181024.1/repos/standard/packages/ + + + +[profile.tizen50m1] +obs = obs.spin +repos = repo.tizen50m1_base, repo.tizen50m1_standard + +[repo.tizen50m1_base] +url = http://download.tizen.org/releases/milestone/tizen/base/tizen-base_20180518.1/repos/standard/packages/ + +[repo.tizen50m1_standard] +url = http://download.tizen.org/releases/milestone/tizen/unified/tizen-unified_20180528.1/repos/standard/packages/ + + +# for platform developer +[profile.tizen50] +obs = obs.spin +repos = repo.tizen_local, repo.tizen50_base, repo.tizen50_standard + +[repo.tizen50_base] +url = http://download.tizen.org/snapshots/tizen/base/latest/repos/standard/packages/ + +[repo.tizen50_standard] +url = http://download.tizen.org/snapshots/tizen/unified/latest/repos/standard/packages/ + + + +[profile.tizen40m3] +obs = obs.spin +repos = repo.tizen40m3_base, repo.tizen40m3_standard + +[repo.tizen40m3_base] +url = http://download.tizen.org/releases/milestone/tizen/4.0-base/tizen-4.0-base_20180817.1/repos/arm/packages + +[repo.tizen40m3_standard] +url = http://download.tizen.org/releases/milestone/tizen/4.0-unified/tizen-4.0-unified_20180821.6/repos/standard/packages/ + + + +[repo.tizen_local] +url = ~/GBS-ROOT/local/repos/tizen50/ + +[obs.spin] +url = http://168.219.209.58:81 + +[obs.tizen] +url = https://api.tizen.org +user = obs_viewer +passwdx = QlpoOTFBWSZTWRP5nYMAAB6fgCAAeUA9mr+QBvzF4CAAVGAZDTRoDI0YBlCKeptQBoA0aGZIAottAkltEPOK7BAFXE9mTUzocPMzQRkPoPpNwEZx3rRQhxkXmGHS6wCjHskyVCP4u5IpwoSAn8zsGA== + diff --git a/config/tizen/template/IoTjsApp/description.xml b/config/tizen/template/IoTjsApp/description.xml new file mode 100644 index 0000000000..e24c0049f1 --- /dev/null +++ b/config/tizen/template/IoTjsApp/description.xml @@ -0,0 +1,25 @@ + + + IoTjs App + 1.0 + + + iot-headless + 4.0 + + + org.tizen.nativecore.buildArtefactType.app + False + + Template + + + ic_s_service.png + ic_m_service_n.png + ic_m_service_s.png + ic_l_service.png + + + This is the empty template for developing IoT.js application. + + diff --git a/config/tizen/template/IoTjsApp/ic_l_service.png b/config/tizen/template/IoTjsApp/ic_l_service.png new file mode 100644 index 0000000000..50e796fb0b Binary files /dev/null and b/config/tizen/template/IoTjsApp/ic_l_service.png differ diff --git a/config/tizen/template/IoTjsApp/ic_m_service_n.png b/config/tizen/template/IoTjsApp/ic_m_service_n.png new file mode 100644 index 0000000000..3c3c4aede9 Binary files /dev/null and b/config/tizen/template/IoTjsApp/ic_m_service_n.png differ diff --git a/config/tizen/template/IoTjsApp/ic_m_service_s.png b/config/tizen/template/IoTjsApp/ic_m_service_s.png new file mode 100644 index 0000000000..02c8c08683 Binary files /dev/null and b/config/tizen/template/IoTjsApp/ic_m_service_s.png differ diff --git a/config/tizen/template/IoTjsApp/ic_s_service.png b/config/tizen/template/IoTjsApp/ic_s_service.png new file mode 100644 index 0000000000..b9820024ed Binary files /dev/null and b/config/tizen/template/IoTjsApp/ic_s_service.png differ diff --git a/config/tizen/template/IoTjsApp/project/inc/main.h b/config/tizen/template/IoTjsApp/project/inc/main.h new file mode 100644 index 0000000000..9d90e54406 --- /dev/null +++ b/config/tizen/template/IoTjsApp/project/inc/main.h @@ -0,0 +1,12 @@ +#ifndef __$(appName)_H__ +#define __$(appName)_H__ + +#include + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "$(appName)" + + +#endif /* __$(appName)_H__ */ diff --git a/config/tizen/template/IoTjsApp/project/project_def.prop b/config/tizen/template/IoTjsApp/project/project_def.prop new file mode 100644 index 0000000000..32b9507608 --- /dev/null +++ b/config/tizen/template/IoTjsApp/project/project_def.prop @@ -0,0 +1,11 @@ +APPNAME = $(appName) + +type = app +profile = $(platform) + +USER_SRCS = src/$(appName).c +USER_DEFS = +USER_INC_DIRS = inc +USER_OBJS = +USER_LIBS = +USER_EDCS = diff --git a/config/tizen/template/IoTjsApp/project/res/index.js b/config/tizen/template/IoTjsApp/project/res/index.js new file mode 100644 index 0000000000..8e0c1bbf8b --- /dev/null +++ b/config/tizen/template/IoTjsApp/project/res/index.js @@ -0,0 +1,2 @@ +console.log('Hello IoT.js'); + diff --git a/config/tizen/template/IoTjsApp/project/src/main.c b/config/tizen/template/IoTjsApp/project/src/main.c new file mode 100644 index 0000000000..c7dcb84459 --- /dev/null +++ b/config/tizen/template/IoTjsApp/project/src/main.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include "$(appName).h" + + +bool service_app_create(void *data) +{ + // Todo: add your code here. + return true; +} + +void service_app_terminate(void *data) +{ + // Todo: add your code here. + return; +} + +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; +} + +static void +service_app_lang_changed(app_event_info_h event_info, void *user_data) +{ + /*APP_EVENT_LANGUAGE_CHANGED*/ + return; +} + +static void +service_app_region_changed(app_event_info_h event_info, void *user_data) +{ + /*APP_EVENT_REGION_FORMAT_CHANGED*/ +} + +static void +service_app_low_battery(app_event_info_h event_info, void *user_data) +{ + /*APP_EVENT_LOW_BATTERY*/ +} + +static void +service_app_low_memory(app_event_info_h event_info, void *user_data) +{ + /*APP_EVENT_LOW_MEMORY*/ +} + +int main(int argc, char* argv[]) +{ + char ad[50] = {0,}; + service_app_lifecycle_callback_s event_callback; + app_event_handler_h handlers[5] = {NULL, }; + + event_callback.create = service_app_create; + event_callback.terminate = service_app_terminate; + event_callback.app_control = service_app_control; + + service_app_add_event_handler(&handlers[APP_EVENT_LOW_BATTERY], APP_EVENT_LOW_BATTERY, service_app_low_battery, &ad); + service_app_add_event_handler(&handlers[APP_EVENT_LOW_MEMORY], APP_EVENT_LOW_MEMORY, service_app_low_memory, &ad); + service_app_add_event_handler(&handlers[APP_EVENT_LANGUAGE_CHANGED], APP_EVENT_LANGUAGE_CHANGED, service_app_lang_changed, &ad); + service_app_add_event_handler(&handlers[APP_EVENT_REGION_FORMAT_CHANGED], APP_EVENT_REGION_FORMAT_CHANGED, service_app_region_changed, &ad); + + return iotjs_service_app_start(argc, argv, "index.js", &event_callback, ad); +} diff --git a/config/tizen/template/IoTjsApp/project/tizen-manifest.xml b/config/tizen/template/IoTjsApp/project/tizen-manifest.xml new file mode 100644 index 0000000000..956edd5f04 --- /dev/null +++ b/config/tizen/template/IoTjsApp/project/tizen-manifest.xml @@ -0,0 +1,17 @@ + + + + + $(appName).png + + + + + http://tizen.org/privilege/network.get + http://tizen.org/privilege/network.set + http://tizen.org/privilege/internet + http://tizen.org/privilege/alarm.set + http://tizen.org/privilege/network.profile + http://tizen.org/privilege/peripheralio + + diff --git a/config/tizen/template/IoTjsApp/sample.xml b/config/tizen/template/IoTjsApp/sample.xml new file mode 100644 index 0000000000..f201e13a61 --- /dev/null +++ b/config/tizen/template/IoTjsApp/sample.xml @@ -0,0 +1,51 @@ + + diff --git a/config/tizenrt/Kconfig.runtime b/config/tizenrt/Kconfig.runtime new file mode 100644 index 0000000000..9b4cee00cf --- /dev/null +++ b/config/tizenrt/Kconfig.runtime @@ -0,0 +1,34 @@ +# +# For a description of the syntax of this configuration file, +# see kconfig-language at https://www.kernel.org/doc/Documentation/kbuild/kconfig-language.txt +# + +config ENABLE_IOTJS + bool "IoT.js" + default n + select SPI_EXCHANGE + select IOTBUS + select IOTBUS_GPIO + select IOTBUS_I2C + select IOTBUS_PWM + select IOTBUS_SPI + select IOTBUS_UART + ---help--- + Enable IoT.js framework + +if ENABLE_IOTJS + +config IOTJS_PRIORITY + int "IoT.js task priority" + default 100 + +config IOTJS_STACKSIZE + int "IoT.js stack size" + default 32768 + +config IOTJS_JERRY_HEAP + int "Jerryscript Heaplimit" + default 128 + +endif #ENABLE_IOTJS + diff --git a/config/tizenrt/Makefile b/config/tizenrt/Makefile new file mode 100644 index 0000000000..14b919dd98 --- /dev/null +++ b/config/tizenrt/Makefile @@ -0,0 +1,58 @@ +########################################################################### +# +# Copyright 2018 Samsung Electronics All Rights Reserved. +# +# 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 $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs + +IOTJS_ROOT_DIR ?= $(TOPDIR)/$(EXTDIR)/iotjs +IOTJS_BUILD_OPTION ?= +ifeq ($(CONFIG_DEBUG),y) + IOTJS_BUILDTYPE = debug +else + IOTJS_BUILDTYPE = release +endif +IOTJS_OS ?= tizenrt +IOTJS_ARCH ?= arm +IOTJS_BUILDCONFIG ?= ${IOTJS_ARCH}-${IOTJS_OS} +IOTJS_LIB_DIR ?= $(IOTJS_ROOT_DIR)/build/${IOTJS_BUILDCONFIG}/$(IOTJS_BUILDTYPE)/lib +IOTJS_ROOT_DIR ?= . +IOTJS_PROFILE_FILE ?= ${IOTJS_ROOT_DIR}/test/profiles/tizenrt.profile + +all: build +.PHONY: depend clean distclean + +${TOPDIR}/include/sys/uio.h: + @mkdir -p ${@D} + @echo "#include " > $@ + +build: $(IOTJS_ROOT_DIR)/tools/build.py ${IOTJS_PROFILE_FILE} ${TOPDIR}/include/sys/uio.h + $(Q) python $< \ + --target-arch=$(CONFIG_ARCH) \ + --target-os=${IOTJS_OS} \ + --sysroot=$(TOPDIR) --target-board=$(CONFIG_ARCH_BOARD) --jerry-heaplimit=$(CONFIG_IOTJS_JERRY_HEAP) \ + --buildtype=$(IOTJS_BUILDTYPE) --no-init-submodule $(IOTJS_BUILD_OPTION) \ + --profile ${IOTJS_PROFILE_FILE} + $(Q) cp $(IOTJS_LIB_DIR)/*.a $(IOTJS_ROOT_DIR) + +depend: + +clean: + $(Q) $(call DELDIR, $(IOTJS_ROOT_DIR)/build) + $(Q) $(call DELFILE, $(IOTJS_ROOT_DIR)/*.a) + +distclean: diff --git a/config/tizenrt/artik05x/app/.gitignore b/config/tizenrt/artik05x/app/.gitignore deleted file mode 100644 index fa1ec75792..0000000000 --- a/config/tizenrt/artik05x/app/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -/Make.dep -/.depend -/.built -/*.asm -/*.obj -/*.rel -/*.lst -/*.sym -/*.adb -/*.lib -/*.src diff --git a/config/tizenrt/artik05x/app/Kconfig b/config/tizenrt/artik05x/app/Kconfig deleted file mode 100644 index 9538b6decd..0000000000 --- a/config/tizenrt/artik05x/app/Kconfig +++ /dev/null @@ -1,27 +0,0 @@ -# -# For a description of the syntax of this configuration file, -# see the file kconfig-language.txt in the NuttX tools repository. -# - -config SYSTEM_IOTJS - bool "IoT.js" - default y - ---help--- - Enable IoT.js platform - -if SYSTEM_IOTJS - -config IOTJS_PRIORITY - int "IoT.js task priority" - default 100 - -config IOTJS_STACKSIZE - int "IoT.js stack size" - default 32768 - -endif - -config USER_ENTRYPOINT - string - default "iotjs_main" if ENTRY_IOTJS - diff --git a/config/tizenrt/artik05x/app/Kconfig_ENTRY b/config/tizenrt/artik05x/app/Kconfig_ENTRY deleted file mode 100644 index 94c48db945..0000000000 --- a/config/tizenrt/artik05x/app/Kconfig_ENTRY +++ /dev/null @@ -1,3 +0,0 @@ -config ENTRY_IOTJS - bool "iotjs application" - depends on SYSTEM_IOTJS diff --git a/config/tizenrt/artik05x/app/Makefile b/config/tizenrt/artik05x/app/Makefile deleted file mode 100644 index 8ef62e00c3..0000000000 --- a/config/tizenrt/artik05x/app/Makefile +++ /dev/null @@ -1,172 +0,0 @@ -########################################################################### -# -# Copyright 2016 Samsung Electronics All Rights Reserved. -# -# 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. -# -########################################################################### -############################################################################ -# apps/examples/iotjs/Makefile -# -# Copyright (C) 2008, 2010-2013 Gregory Nutt. All rights reserved. -# Author: Gregory Nutt -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# 3. Neither the name NuttX nor the names of its contributors may be -# used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -############################################################################ - -EXTRA_LIBPATHS += -L$(IOTJS_LIB_DIR) -EXTRA_LIBS += libhttpparser.a libiotjs.a libjerrycore.a libtuv.a libjerry-libm.a - -LINKLIBS=$(EXTRA_LIBS) - --include $(TOPDIR)/.config --include $(TOPDIR)/Make.defs -include $(APPDIR)/Make.defs - - -# IoT.js application -CONFIG_IOTJS_PRIORITY ?= SCHED_PRIORITY_DEFAULT -CONFIG_IOTJS_STACKSIZE ?= 16384 -IOTJS_LIB_DIR ?= n - -APPNAME = iotjs -PRIORITY = $(CONFIG_IOTJS_PRIORITY) -STACKSIZE = $(CONFIG_IOTJS_STACKSIZE) -HEAPSIZE = $(CONFIG_IOTJS_HEAPSIZE) - -ASRCS = -CSRCS = -MAINSRC = iotjs_main.c - -AOBJS = $(ASRCS:.S=$(OBJEXT)) -COBJS = $(CSRCS:.c=$(OBJEXT)) -MAINOBJ = $(MAINSRC:.c=$(OBJEXT)) - -SRCS = $(ASRCS) $(CSRCS) $(MAINSRC) -OBJS = $(AOBJS) $(COBJS) - -ifeq ($(R),1) - BUILD_TYPE = release -else - BUILD_TYPE = debug -endif - -ifneq ($(CONFIG_BUILD_KERNEL),y) - OBJS += $(MAINOBJ) -endif - -ifeq ($(CONFIG_WINDOWS_NATIVE),y) - BIN = ..\..\libapps$(LIBEXT) -else -ifeq ($(WINTOOL),y) - BIN = ..\\..\\libapps$(LIBEXT) -else - BIN = ../../libapps$(LIBEXT) -endif -endif - -ifeq ($(WINTOOL),y) - INSTALL_DIR = "${shell cygpath -w $(BIN_DIR)}" -else - INSTALL_DIR = $(BIN_DIR) -endif - -CONFIG_IOTJS_PROGNAME ?= iotjs$(EXEEXT) -PROGNAME = $(CONFIG_IOTJS_PROGNAME) - -ROOTDEPPATH = --dep-path . - -# Common build - -VPATH = - -all: .built -.PHONY: clean depend distclean check_iotjs - -$(AOBJS): %$(OBJEXT): %.S - $(call ASSEMBLE, $<, $@) - -$(COBJS) $(MAINOBJ): %$(OBJEXT): %.c - $(call COMPILE, $<, $@) - -.built: $(OBJS) check_iotjs - $(call ARCHIVE, $(BIN), $(OBJS)) - @touch .built - -ifeq ($(CONFIG_BUILD_KERNEL),y) -$(BIN_DIR)$(DELIM)$(PROGNAME): $(OBJS) $(MAINOBJ) check_iotjs - $(Q) $(LD) $(LDELFFLAGS) $(LDLIBPATH) -o $(INSTALL_DIR)$(DELIM)$(PROGNAME) $(ARCHCRT0OBJ) $(MAINOBJ) $(LDLIBS) - $(Q) $(NM) -u $(INSTALL_DIR)$(DELIM)$(PROGNAME) - -install: $(BIN_DIR)$(DELIM)$(PROGNAME) - -else -install: - -endif - -check_iotjs: -ifeq ($(IOTJS_LIB_DIR),n) - @echo "ERROR: IOTJS_LIB_DIR not set! Aborting..." - @exit 1 -endif - @echo IOTJS_LIB_DIR set! - @echo "$(LDLIBPATH), $(IOTJS_LIB_DIR) $(TOPDIR)" - @cp $(IOTJS_LIB_DIR)/lib* $(TOPDIR)/../build/output/libraries/ - @cp $(IOTJS_LIB_DIR)/../deps/jerry/lib/libjerry-libm.a $(TOPDIR)/../build/output/libraries/ - -context: - -.depend: Makefile $(SRCS) - @$(MKDEP) $(ROOTDEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep - @touch $@ - -depend: .depend - -clean: - $(call DELFILE, .built) - $(call CLEAN) - -distclean: clean - $(call DELFILE, Make.dep) - $(call DELFILE, .depend) - --include Make.dep -.PHONY: preconfig -preconfig: diff --git a/config/tizenrt/artik05x/app/iotjs_main.c b/config/tizenrt/artik05x/app/iotjs_main.c deleted file mode 100644 index e1b6807729..0000000000 --- a/config/tizenrt/artik05x/app/iotjs_main.c +++ /dev/null @@ -1,162 +0,0 @@ -/* Copyright 2015-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. - */ - -/**************************************************************************** - * Copyright (C) 2013 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include -#include -#include - -#include -#include - -#define USE_IOTJS_THREAD 1 - -/** - * Compiler built-in setjmp function. - * - * @return 0 when called the first time - * 1 when returns from a longjmp call - */ - -int setjmp(jmp_buf buf) { - return __builtin_setjmp(buf); -} /* setjmp */ - -/** - * Compiler built-in longjmp function. - * - * Note: - * ignores value argument - */ - -void longjmp(jmp_buf buf, int value) { - /* Must be called with 1. */ - __builtin_longjmp(buf, 1); -} /* longjmp */ - -int iotjs_entry(int argc, char *argv[]); -int tuv_cleanup(void); - - -#if USE_IOTJS_THREAD -struct iotjs_thread_arg { - int argc; - char **argv; -}; - -pthread_addr_t iotjs_thread(void *thread_arg) { - struct iotjs_thread_arg *arg = thread_arg; - int ret = 0; - - ret = iotjs_entry(arg->argc, arg->argv); - tuv_cleanup(); - - sleep(1); - printf("iotjs thread end\n"); - return NULL; -} - -int iotjs(int argc, char *argv[]) { - pthread_attr_t attr; - int status; - struct sched_param sparam; - pthread_t tid; - struct iotjs_thread_arg arg; - - status = pthread_attr_init(&attr); - if (status != 0) { - printf("fail to initialize iotjs thread\n"); - return -1; - } - - sparam.sched_priority = CONFIG_IOTJS_PRIORITY; - status = pthread_attr_setschedparam(&attr, &sparam); - status = pthread_attr_setschedpolicy(&attr, SCHED_RR); - status = pthread_attr_setstacksize(&attr, CONFIG_IOTJS_STACKSIZE); - - arg.argc = argc; - arg.argv = argv; - - status = pthread_create(&tid, &attr, iotjs_thread, &arg); - if (status < 0) { - printf("fail to start iotjs thread\n"); - return -1; - } - pthread_setname_np(tid, "iotjs_thread"); - pthread_join(tid, NULL); - - return 0; -} - -#else - -static int iotjs(int argc, char *argv[]) { - int ret = 0; - ret = iotjs_entry(argc, argv); - tuv_cleanup(); - return ret; -} - -#endif - -#ifdef CONFIG_BUILD_KERNEL -int main(int argc, FAR char *argv[]) -#else -int iotjs_main(int argc, char *argv[]) -#endif -{ - return iotjs(argc, argv); -} - -int iotjs_register_cmd() { - tash_cmd_install("iotjs", iotjs, TASH_EXECMD_SYNC); - return 0; -} diff --git a/config/tizenrt/artik05x/configs/debug/defconfig b/config/tizenrt/artik05x/configs/debug/defconfig new file mode 100644 index 0000000000..a9e801c08c --- /dev/null +++ b/config/tizenrt/artik05x/configs/debug/defconfig @@ -0,0 +1,1308 @@ +# +# Automatically generated file; DO NOT EDIT. +# TinyAra Configuration +# + +# +# Build Setup +# +# CONFIG_EXPERIMENTAL is not set +# CONFIG_DEFAULT_SMALL is not set +CONFIG_HOST_LINUX=y +# CONFIG_HOST_OSX is not set +# CONFIG_HOST_WINDOWS is not set +# CONFIG_HOST_OTHER is not set +# CONFIG_WINDOWS_NATIVE is not set + +# +# Build Configuration +# +CONFIG_APPS_DIR="../apps" +CONFIG_FRAMEWORK_DIR="../framework" +CONFIG_TOOLS_DIR="../tools" +CONFIG_BUILD_FLAT=y +# CONFIG_BUILD_PROTECTED is not set +# CONFIG_BUILD_2PASS is not set + +# +# Binary Output Formats +# +# CONFIG_INTELHEX_BINARY is not set +# CONFIG_MOTOROLA_SREC is not set +CONFIG_RAW_BINARY=y +# CONFIG_UBOOT_UIMAGE is not set +# CONFIG_DOWNLOAD_IMAGE is not set +# CONFIG_SMARTFS_IMAGE is not set + +# +# Customize Header Files +# +# CONFIG_ARCH_STDINT_H is not set +# CONFIG_ARCH_STDBOOL_H is not set +# CONFIG_ARCH_MATH_H is not set +# CONFIG_ARCH_FLOAT_H is not set +# CONFIG_ARCH_STDARG_H is not set +CONFIG_ARCH_HAVE_CUSTOMOPT=y +# CONFIG_DEBUG_NOOPT is not set +# CONFIG_DEBUG_CUSTOMOPT is not set +CONFIG_DEBUG_FULLOPT=y + +# +# Hardware Configuration +# + +# +# Chip Selection +# +CONFIG_ARCH_ARM=y +CONFIG_ARCH="arm" +# CONFIG_ARCH_CHIP_LM is not set +CONFIG_ARCH_CHIP_S5J=y +# CONFIG_ARCH_CHIP_BCM4390X is not set +CONFIG_ARCH_CHIP="s5j" + +# +# ARM Options +# +# CONFIG_ARCH_CORTEXM3 is not set +# CONFIG_ARCH_CORTEXM4 is not set +CONFIG_ARCH_CORTEXR4=y +CONFIG_ARCH_FAMILY="armv7-r" +# CONFIG_ARCH_HAVE_FPU is not set +CONFIG_ARMV7M_MPU=y +CONFIG_ARMV7M_MPU_NREGIONS=12 + +# +# Exception stack options +# +CONFIG_ARCH_HAVE_DABORTSTACK=y +CONFIG_ARCH_DABORTSTACK=0 + +# +# ARMv7-R Configuration Options +# +CONFIG_ARMV7R_HAVE_GICv2=y +CONFIG_ARMV7R_MEMINIT=y +CONFIG_ARMV7R_ICACHE=y +CONFIG_ARMV7R_DCACHE=y +# CONFIG_ARMV7R_DCACHE_WRITETHROUGH is not set +# CONFIG_ARMV7R_HAVE_L2CC is not set +# CONFIG_ARMV7R_HAVE_L2CC_PL310 is not set +# CONFIG_ARMV7R_TOOLCHAIN_BUILDROOT is not set +# CONFIG_ARMV7R_TOOLCHAIN_CODESOURCERYL is not set +CONFIG_ARMV7R_TOOLCHAIN_GNU_EABIL=y +# CONFIG_ARMV7R_TOOLCHAIN_GNU_OABI is not set +# CONFIG_ARMV7R_HAVE_DECODEFIQ is not set + +# +# S5J Configuration Options +# +CONFIG_ARCH_CHIP_S5JT200=y +CONFIG_S5J_S5JT200=y + +# +# S5J Peripheral Support +# +CONFIG_S5J_HAVE_ADC=y +CONFIG_S5J_HAVE_DMA=y +CONFIG_S5J_HAVE_I2C=y +CONFIG_S5J_HAVE_I2S=y +CONFIG_S5J_HAVE_MCT=y +CONFIG_S5J_HAVE_PWM0=y +CONFIG_S5J_HAVE_PWM1=y +CONFIG_S5J_HAVE_PWM2=y +CONFIG_S5J_HAVE_PWM3=y +CONFIG_S5J_HAVE_PWM4=y +CONFIG_S5J_HAVE_PWM5=y +CONFIG_S5J_HAVE_RTC=y +CONFIG_S5J_HAVE_SFLASH=y +CONFIG_S5J_HAVE_SPI=y +CONFIG_S5J_HAVE_SSS=y +CONFIG_S5J_HAVE_UART0=y +CONFIG_S5J_HAVE_UART1=y +CONFIG_S5J_HAVE_UART2=y +CONFIG_S5J_HAVE_UART3=y +CONFIG_S5J_HAVE_UART4=y +CONFIG_S5J_HAVE_WATCHDOG=y +CONFIG_S5J_ADC=y +# CONFIG_S5J_DMA is not set +CONFIG_S5J_I2C=y +# CONFIG_S5J_I2S is not set +CONFIG_S5J_MCT=y +CONFIG_S5J_TIMER0=y +# CONFIG_S5J_TIMER1 is not set +# CONFIG_S5J_TIMER2 is not set +# CONFIG_S5J_TIMER3 is not set +# CONFIG_S5J_UART_FLOWCONTROL is not set +CONFIG_S5J_UART0=y +CONFIG_S5J_UART1=y +CONFIG_S5J_UART2=y +CONFIG_S5J_UART3=y +CONFIG_S5J_UART4=y +CONFIG_S5J_PWM=y +CONFIG_S5J_PWM0=y +CONFIG_S5J_PWM1=y +CONFIG_S5J_PWM2=y +CONFIG_S5J_PWM3=y +CONFIG_S5J_PWM4=y +CONFIG_S5J_PWM5=y +# CONFIG_S5J_SSS is not set +CONFIG_S5J_SPI=y +# CONFIG_S5J_WATCHDOG is not set +CONFIG_S5J_SFLASH=y +# CONFIG_S5J_SENSOR_PPD42NS is not set + +# +# Architecture Options +# +# CONFIG_ARCH_NOINTC is not set +# CONFIG_ARCH_VECNOTIRQ is not set +# CONFIG_ARCH_DMA is not set +# CONFIG_ARCH_HAVE_IRQPRIO is not set +# CONFIG_ARCH_L2CACHE is not set +# CONFIG_ARCH_HAVE_COHERENT_DCACHE is not set +# CONFIG_ARCH_HAVE_ADDRENV is not set +# CONFIG_ARCH_NEED_ADDRENV_MAPPING is not set +CONFIG_ARCH_HAVE_VFORK=y +# CONFIG_ARCH_HAVE_MMU is not set +CONFIG_ARCH_HAVE_MPU=y +# CONFIG_ARCH_NAND_HWECC is not set +# CONFIG_ARCH_HAVE_EXTCLK is not set +# CONFIG_ARCH_HAVE_POWEROFF is not set +CONFIG_ARCH_HAVE_RESET=y +CONFIG_ARCH_USE_MPU=y +CONFIG_ARCH_STACKDUMP=y +# CONFIG_DEBUG_DISPLAY_SYMBOL is not set +# CONFIG_ENDIAN_BIG is not set +# CONFIG_ARCH_IDLE_CUSTOM is not set +CONFIG_ARCH_CUSTOM_PMINIT=y +# CONFIG_ARCH_HAVE_RAMFUNCS is not set +# CONFIG_ARCH_HAVE_RAMVECTORS is not set + +# +# Board Settings +# +CONFIG_BOARD_LOOPSPERMSEC=29100 +# CONFIG_ARCH_CALIBRATION is not set + +# +# Interrupt options +# +CONFIG_ARCH_HAVE_INTERRUPTSTACK=y +CONFIG_ARCH_INTERRUPTSTACK=0 +# CONFIG_ARCH_HAVE_HIPRI_INTERRUPT is not set + +# +# Boot options +# +# CONFIG_BOOT_RUNFROMEXTSRAM is not set +CONFIG_BOOT_RUNFROMFLASH=y +# CONFIG_BOOT_RUNFROMISRAM is not set +# CONFIG_BOOT_RUNFROMSDRAM is not set +# CONFIG_BOOT_COPYTORAM is not set + +# +# Boot Memory Configuration +# +CONFIG_RAM_START=0x02023800 +CONFIG_RAM_SIZE=968704 +# CONFIG_DDR is not set +# CONFIG_ARCH_HAVE_SDRAM is not set + +# +# Board Selection +# +CONFIG_ARCH_BOARD_ARTIK053=y +# CONFIG_ARCH_BOARD_ARTIK053S is not set +# CONFIG_ARCH_BOARD_ARTIK055S is not set +# CONFIG_ARCH_BOARD_SIDK_S5JT200 is not set +CONFIG_ARCH_BOARD_ARTIK05X_FAMILY=y +CONFIG_ARCH_BOARD="artik05x" + +# +# Common Board Options +# +# CONFIG_BOARD_CRASHDUMP is not set +# CONFIG_BOARD_ASSERT_AUTORESET is not set +CONFIG_LIB_BOARDCTL=y +CONFIG_BOARDCTL_RESET=y +# CONFIG_BOARDCTL_UNIQUEID is not set +# CONFIG_BOARD_FOTA_SUPPORT is not set + +# +# Board-Specific Options +# +CONFIG_ARTIK05X_BOOT_FAILURE_DETECTION=y +CONFIG_ARTIK05X_BOOT_COUNTS_ADDR=0x80090810 +CONFIG_ARTIK05X_FLASH_CAPACITY=8388608 +CONFIG_ARTIK05X_FLASH_PAGE_SIZE=4096 +CONFIG_ARTIK05X_FLASH_PART=y +CONFIG_ARTIK05X_FLASH_MINOR=0 +CONFIG_ARTIK05X_FLASH_PART_LIST="16,48,192,32,512,2400,1536,1536,1000,400,8,512," +CONFIG_ARTIK05X_FLASH_PART_TYPE="none,ftl,none,none,none,none,none,ftl,smartfs,romfs,config,none," +CONFIG_ARTIK05X_FLASH_PART_NAME="bl1,sssro,bl2,sssfw,wlanfw,os,factory,ota,user,rom,nvram,sssrw," +CONFIG_ARTIK05X_AUTOMOUNT=y +CONFIG_ARTIK05X_AUTOMOUNT_USERFS=y +CONFIG_ARTIK05X_AUTOMOUNT_USERFS_DEVNAME="/dev/smart0p8" +CONFIG_ARTIK05X_AUTOMOUNT_USERFS_MOUNTPOINT="/mnt" +# CONFIG_ARTIK05X_AUTOMOUNT_SSSRW is not set +CONFIG_ARTIK05X_AUTOMOUNT_ROMFS=y +CONFIG_ARTIK05X_AUTOMOUNT_ROMFS_DEVNAME="/dev/mtdblock9" +CONFIG_ARTIK05X_AUTOMOUNT_ROMFS_MOUNTPOINT="/rom" + +# +# Kernel Features +# +CONFIG_DISABLE_OS_API=y +# CONFIG_DISABLE_POSIX_TIMERS is not set +# CONFIG_DISABLE_PTHREAD is not set +# CONFIG_DISABLE_SIGNALS is not set +# CONFIG_DISABLE_MQUEUE is not set +# CONFIG_DISABLE_ENVIRON is not set + +# +# Clocks and Timers +# +CONFIG_ARCH_HAVE_TICKLESS=y +# CONFIG_SCHED_TICKLESS is not set +CONFIG_USEC_PER_TICK=9979 +CONFIG_SYSTEM_TIME64=y +CONFIG_CLOCK_MONOTONIC=y +# CONFIG_JULIAN_TIME is not set +CONFIG_MAX_WDOGPARMS=4 +CONFIG_PREALLOC_WDOGS=32 +CONFIG_WDOG_INTRESERVE=4 +CONFIG_PREALLOC_TIMERS=8 + +# +# Tasks and Scheduling +# +CONFIG_INIT_ENTRYPOINT=y +CONFIG_RR_INTERVAL=100 +CONFIG_TASK_NAME_SIZE=31 +CONFIG_MAX_TASKS=32 +CONFIG_SCHED_HAVE_PARENT=y +# CONFIG_SCHED_CHILD_STATUS is not set +CONFIG_SCHED_WAITPID=y + +# +# Pthread Options +# +CONFIG_PTHREAD_MUTEX_TYPES=y +# CONFIG_PTHREAD_MUTEX_ROBUST is not set +CONFIG_PTHREAD_MUTEX_UNSAFE=y +# CONFIG_PTHREAD_MUTEX_BOTH is not set +CONFIG_NPTHREAD_KEYS=4 +CONFIG_NPTHREAD_DESTRUCTOR_ITERATIONS=4 +# CONFIG_PTHREAD_CLEANUP is not set +# CONFIG_CANCELLATION_POINTS is not set + +# +# Performance Monitoring +# +# CONFIG_SCHED_CPULOAD is not set + +# +# Latency optimization +# +# CONFIG_SCHED_YIELD_OPTIMIZATION is not set + +# +# Files and I/O +# +CONFIG_DEV_CONSOLE=y +# CONFIG_FDCLONE_DISABLE is not set +# CONFIG_FDCLONE_STDIO is not set +# CONFIG_SDCLONE_DISABLE is not set +CONFIG_NFILE_DESCRIPTORS=16 +CONFIG_NFILE_STREAMS=16 +CONFIG_NAME_MAX=32 +CONFIG_PRIORITY_INHERITANCE=y +CONFIG_SEM_PREALLOCHOLDERS=16 +CONFIG_SEM_NNESTPRIO=16 + +# +# RTOS hooks +# +CONFIG_BOARD_INITIALIZE=y +# CONFIG_BOARD_INITTHREAD is not set +# CONFIG_SCHED_STARTHOOK is not set +CONFIG_SCHED_ATEXIT=y +CONFIG_SCHED_ONEXIT=y + +# +# Signal Numbers +# +CONFIG_SIG_SIGUSR1=1 +CONFIG_SIG_SIGUSR2=2 +CONFIG_SIG_SIGALARM=3 +CONFIG_SIG_SIGCHLD=4 +CONFIG_SIG_SIGCONDTIMEDOUT=16 +CONFIG_SIG_SIGWORK=17 + +# +# POSIX Message Queue Options +# +CONFIG_PREALLOC_MQ_MSGS=4 +CONFIG_MQ_MAXMSGSIZE=600 + +# +# Work Queue Support +# +CONFIG_SCHED_WORKQUEUE=y +CONFIG_SCHED_WORKQUEUE_SORTING=y +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_HPWORKPRIORITY=224 +CONFIG_SCHED_HPWORKPERIOD=50000 +CONFIG_SCHED_HPWORKSTACKSIZE=2048 +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_LPNTHREADS=1 +CONFIG_SCHED_LPWORKPRIORITY=176 +CONFIG_SCHED_LPWORKPRIOMAX=176 +CONFIG_SCHED_LPWORKPERIOD=50000 +CONFIG_SCHED_LPWORKSTACKSIZE=2048 + +# +# Stack size information +# +CONFIG_IDLETHREAD_STACKSIZE=1024 +CONFIG_USERMAIN_STACKSIZE=2048 +# CONFIG_MPU_STACKGAURD is not set +CONFIG_PTHREAD_STACK_MIN=256 +CONFIG_PTHREAD_STACK_DEFAULT=2048 + +# +# Device Drivers +# +# CONFIG_DISABLE_POLL is not set +CONFIG_DEV_NULL=y +CONFIG_DEV_ZERO=y +# CONFIG_DRVR_WRITEBUFFER is not set +# CONFIG_DRVR_READAHEAD is not set +# CONFIG_CAN is not set +# CONFIG_ARCH_HAVE_PWM_PULSECOUNT is not set +# CONFIG_ARCH_HAVE_PWM_MULTICHAN is not set +CONFIG_PWM=y +# CONFIG_ARCH_HAVE_I2CRESET is not set +CONFIG_I2C=y +CONFIG_I2C_SLAVE=y +CONFIG_I2C_USERIO=y +CONFIG_I2C_TRANSFER=y +CONFIG_I2C_POLLED=y +# CONFIG_I2C_TRACE is not set +# CONFIG_I2C_WRITEREAD is not set +CONFIG_SPI=y +# CONFIG_SPI_OWNBUS is not set +CONFIG_SPI_EXCHANGE=y +# CONFIG_SPI_CMDDATA is not set +# CONFIG_SPI_BITBANG is not set +CONFIG_GPIO=y +# CONFIG_I2S is not set +# CONFIG_AUDIO_DEVICES is not set +CONFIG_BCH=y +CONFIG_RTC=y +CONFIG_RTC_DATETIME=y +# CONFIG_RTC_ALARM is not set +CONFIG_RTC_DRIVER=y +# CONFIG_RTC_IOCTL is not set +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_DEVPATH="/dev/watchdog0" +# CONFIG_TIMER is not set +CONFIG_ANALOG=y +CONFIG_ADC=y +CONFIG_ADC_FIFOSIZE=8 +# CONFIG_DAC is not set +CONFIG_NETDEVICES=y + +# +# General Ethernet MAC Driver Options +# +CONFIG_NETDEV_TELNET=y +CONFIG_NETDEV_MULTINIC=y +# CONFIG_NET_DUMPPACKET is not set + +# +# External Ethernet MAC Device Support +# +# CONFIG_NET_DM90x0 is not set +# CONFIG_ENC28J60 is not set +# CONFIG_ENCX24J600 is not set +# CONFIG_NET_E1000 is not set +# CONFIG_NET_SLIP is not set +# CONFIG_NET_VNET is not set +# CONFIG_PIPES is not set +CONFIG_POWER=y +# CONFIG_BATTERY_CHARGER is not set +# CONFIG_BATTERY_GAUGE is not set +CONFIG_SERIAL=y +# CONFIG_DEV_LOWCONSOLE is not set +# CONFIG_16550_UART is not set +# CONFIG_ARCH_HAVE_UART is not set +CONFIG_ARCH_HAVE_UART0=y +CONFIG_ARCH_HAVE_UART1=y +CONFIG_ARCH_HAVE_UART2=y +CONFIG_ARCH_HAVE_UART3=y +CONFIG_ARCH_HAVE_UART4=y +# CONFIG_ARCH_HAVE_UART5 is not set +# CONFIG_ARCH_HAVE_UART6 is not set +# CONFIG_ARCH_HAVE_UART7 is not set +# CONFIG_ARCH_HAVE_UART8 is not set +# CONFIG_ARCH_HAVE_SCI0 is not set +# CONFIG_ARCH_HAVE_SCI1 is not set +# CONFIG_ARCH_HAVE_USART0 is not set +# CONFIG_ARCH_HAVE_USART1 is not set +# CONFIG_ARCH_HAVE_USART2 is not set +# CONFIG_ARCH_HAVE_USART3 is not set +# CONFIG_ARCH_HAVE_USART4 is not set +# CONFIG_ARCH_HAVE_USART5 is not set +# CONFIG_ARCH_HAVE_USART6 is not set +# CONFIG_ARCH_HAVE_USART7 is not set +# CONFIG_ARCH_HAVE_USART8 is not set +# CONFIG_ARCH_HAVE_OTHER_UART is not set + +# +# USART Configuration +# +CONFIG_MCU_SERIAL=y +CONFIG_STANDARD_SERIAL=y +CONFIG_SERIAL_NPOLLWAITERS=2 +# CONFIG_SERIAL_IFLOWCONTROL is not set +# CONFIG_SERIAL_OFLOWCONTROL is not set +# CONFIG_SERIAL_TIOCSERGSTRUCT is not set +CONFIG_ARCH_HAVE_SERIAL_TERMIOS=y +CONFIG_SERIAL_TERMIOS=y +# CONFIG_UART0_SERIAL_CONSOLE is not set +# CONFIG_UART1_SERIAL_CONSOLE is not set +# CONFIG_UART2_SERIAL_CONSOLE is not set +# CONFIG_UART3_SERIAL_CONSOLE is not set +CONFIG_UART4_SERIAL_CONSOLE=y +# CONFIG_OTHER_SERIAL_CONSOLE is not set +# CONFIG_NO_SERIAL_CONSOLE is not set + +# +# UART0 Configuration +# +CONFIG_UART0_RXBUFSIZE=64 +CONFIG_UART0_TXBUFSIZE=64 +CONFIG_UART0_BAUD=115200 +CONFIG_UART0_BITS=8 +CONFIG_UART0_PARITY=0 +CONFIG_UART0_2STOP=0 +# CONFIG_UART0_IFLOWCONTROL is not set +# CONFIG_UART0_OFLOWCONTROL is not set + +# +# UART1 Configuration +# +CONFIG_UART1_RXBUFSIZE=256 +CONFIG_UART1_TXBUFSIZE=256 +CONFIG_UART1_BAUD=115200 +CONFIG_UART1_BITS=8 +CONFIG_UART1_PARITY=0 +CONFIG_UART1_2STOP=0 +# CONFIG_UART1_IFLOWCONTROL is not set +# CONFIG_UART1_OFLOWCONTROL is not set + +# +# UART2 Configuration +# +CONFIG_UART2_RXBUFSIZE=256 +CONFIG_UART2_TXBUFSIZE=256 +CONFIG_UART2_BAUD=115200 +CONFIG_UART2_BITS=8 +CONFIG_UART2_PARITY=0 +CONFIG_UART2_2STOP=0 +# CONFIG_UART2_IFLOWCONTROL is not set +# CONFIG_UART2_OFLOWCONTROL is not set + +# +# UART3 Configuration +# +CONFIG_UART3_RXBUFSIZE=256 +CONFIG_UART3_TXBUFSIZE=256 +CONFIG_UART3_BAUD=115200 +CONFIG_UART3_BITS=8 +CONFIG_UART3_PARITY=0 +CONFIG_UART3_2STOP=0 +# CONFIG_UART3_IFLOWCONTROL is not set +# CONFIG_UART3_OFLOWCONTROL is not set + +# +# UART4 Configuration +# +CONFIG_UART4_RXBUFSIZE=256 +CONFIG_UART4_TXBUFSIZE=256 +CONFIG_UART4_BAUD=115200 +CONFIG_UART4_BITS=8 +CONFIG_UART4_PARITY=0 +CONFIG_UART4_2STOP=0 +# CONFIG_UART4_IFLOWCONTROL is not set +# CONFIG_UART4_OFLOWCONTROL is not set +# CONFIG_SENSOR is not set +# CONFIG_USBDEV is not set +# CONFIG_FOTA_DRIVER is not set + +# +# System Logging +# +# CONFIG_RAMLOG is not set +# CONFIG_SYSLOG_CONSOLE is not set + +# +# T-trace +# +# CONFIG_TTRACE is not set + +# +# Wireless Device Options +# +CONFIG_DRIVERS_WIRELESS=y +CONFIG_SCSC_WLAN=y +# CONFIG_SLSI_RX_PERFORMANCE_TEST is not set +CONFIG_SCSC_TX_FLOW_CONTROL=y +CONFIG_SCSC_ENABLE_PORT_CONTROL=y +# CONFIG_SCSC_WLAN_STA_ONLY is not set +# CONFIG_SCSC_WLAN_BLOCK_IPV6 is not set +# CONFIG_SCSC_WLAN_UDP_FLOWCONTROL is not set +# CONFIG_SCSC_WLAN_AUTO_RECOVERY is not set +CONFIG_SCSC_WLAN_POWER_SAVE=y +CONFIG_SCSC_WLAN_MAX_INTERFACES=1 +CONFIG_SCSC_CORE=y +CONFIG_SCSC_PLATFORM=y +# CONFIG_SCSC_WLANLITE is not set +# CONFIG_SCSC_DISABLE_WLAN_RESET is not set + +# +# Networking Support +# +CONFIG_ARCH_HAVE_NET=y +# CONFIG_ARCH_HAVE_PHY is not set +CONFIG_NET=y +CONFIG_NET_LWIP=y + +# +# LwIP options +# +CONFIG_NET_IPv4=y +CONFIG_NET_IP_DEFAULT_TTL=255 +# CONFIG_NET_IP_FORWARD is not set +CONFIG_NET_IP_OPTIONS_ALLOWED=y +CONFIG_NET_IP_FRAG=y +CONFIG_NET_IP_REASSEMBLY=y +CONFIG_NET_IPV4_REASS_MAX_PBUFS=20 +CONFIG_NET_IPV4_REASS_MAXAGE=5 +CONFIG_NET_IPv6=y +CONFIG_NET_IPv6_NUM_ADDRESSES=3 +# CONFIG_NET_IPv6_FORWARD is not set +# CONFIG_NET_IPv6_FRAG is not set +CONFIG_NET_IPv6_REASS=y +CONFIG_NET_IPV6_REASS_MAXAGE=60 +CONFIG_NET_IPv6_SEND_ROUTER_SOLICIT=y +CONFIG_NET_IPv6_AUTOCONFIG=y +CONFIG_NET_IPv6_DUP_DETECT_ATTEMPTS=1 +# CONFIG_NET_IPv6_PMTU_FOR_MULTICAST is not set + +# +# Socket support +# +CONFIG_NET_SOCKET=y +CONFIG_NSOCKET_DESCRIPTORS=20 +CONFIG_NET_TCP_KEEPALIVE=y +CONFIG_NET_RAW=y +# CONFIG_NET_SOCKET_OPTION_BROADCAST is not set +# CONFIG_NET_RANDOMIZE_INITIAL_LOCAL_PORTS is not set +# CONFIG_NET_SO_SNDTIMEO is not set +CONFIG_NET_SO_RCVTIMEO=y +# CONFIG_NET_SO_RCVBUF is not set +CONFIG_NET_SO_REUSE=y +# CONFIG_NET_SO_REUSE_RXTOALL is not set +CONFIG_NET_ARP=y +CONFIG_NET_ARP_TABLESIZE=10 +CONFIG_NET_ARP_QUEUEING=y +CONFIG_NET_ETHARP_TRUST_IP_MAC=y +CONFIG_NET_ETH_PAD_SIZE=0 +# CONFIG_NET_ARP_STATIC_ENTRIES is not set +CONFIG_NET_IPv6_ND=y +CONFIG_NET_IPv6_ND_QUEUEING=y +CONFIG_NET_IPv6_ND_QUEUE=20 +CONFIG_NET_IPv6_ND_NUM_NEIGHBORS=10 +CONFIG_NET_IPv6_ND_NUM_DESTINATIONS=10 +CONFIG_NET_IPv6_ND_NUM_PREFIXES=5 +CONFIG_NET_IPv6_ND_NUM_ROUTERS=3 +CONFIG_NET_IPv6_ND_MAX_MULTICAST_SOLICIT=3 +CONFIG_NET_IPv6_ND_MAX_UNICAST_SOLICIT=3 +CONFIG_NET_IPv6_ND_MAX_SOLICIT_INTERVAL=4000 +CONFIG_NET_IPv6_ND_REACHABLE_TIME=30000 +CONFIG_NET_IPv6_ND_RETRANS_TIMER=1000 +CONFIG_NET_IPv6_ND_DELAY_FIRST_PROBE_TIME=5000 +CONFIG_NET_IPv6_ND_ALLOW_RA_UPDATES=y +CONFIG_NET_IPv6_ND_TCP_REACHABILITY_HINTS=y +CONFIG_NET_IPv6_ND_RDNSS_MAX_DNS_SERVERS=0 +CONFIG_NET_UDP=y +# CONFIG_NET_NETBUF_RECVINFO is not set +CONFIG_NET_UDP_TTL=255 +# CONFIG_NET_UDPLITE is not set +CONFIG_NET_TCP=y +CONFIG_NET_TCP_TTL=255 +CONFIG_NET_TCP_WND=58400 +CONFIG_NET_TCP_MAXRTX=12 +CONFIG_NET_TCP_SYNMAXRTX=6 +CONFIG_NET_TCP_QUEUE_OOSEQ=y +CONFIG_NET_TCP_MSS=1460 +CONFIG_NET_TCP_CALCULATE_EFF_SEND_MSS=y +CONFIG_NET_TCP_SND_BUF=29200 +CONFIG_NET_TCP_SND_QUEUELEN=80 +# CONFIG_NET_TCP_LISTEN_BACKLOG is not set +CONFIG_NET_TCP_OVERSIZE=536 +# CONFIG_NET_TCP_TIMESTAMPS is not set +CONFIG_NET_TCP_WND_UPDATE_THRESHOLD=536 +CONFIG_NET_ICMP=y +CONFIG_NET_ICMP_TTL=255 +# CONFIG_NET_BROADCAST_PING is not set +# CONFIG_NET_MULTICAST_PING4 is not set +CONFIG_NET_IPv6_ICMP=y +CONFIG_NET_IPv6_ICMP_DATASIZE=8 +CONFIG_NET_IPv6_ICMP_HL=255 +# CONFIG_NET_MULTICAST_PING6 is not set +CONFIG_NET_LWIP_IGMP=y +CONFIG_NET_LWIP_MEMP_NUM_IGMP_GROUP=8 +CONFIG_NET_IPv6_MLD=y +CONFIG_NET_IPv6_MLD_GROUP=4 +# CONFIG_NET_IPv6_DHCP is not set + +# +# LWIP Mailbox Configurations +# +CONFIG_NET_TCPIP_MBOX_SIZE=64 +CONFIG_NET_DEFAULT_ACCEPTMBOX_SIZE=64 +CONFIG_NET_DEFAULT_RAW_RECVMBOX_SIZE=64 +CONFIG_NET_DEFAULT_TCP_RECVMBOX_SIZE=54 +CONFIG_NET_DEFAULT_UDP_RECVMBOX_SIZE=64 + +# +# Memory Configurations +# +CONFIG_NET_MEM_ALIGNMENT=4 +# CONFIG_NET_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT is not set +# CONFIG_NET_MEM_LIBC_MALLOC is not set +CONFIG_NET_MEMP_MEM_MALLOC=y +# CONFIG_NET_MEM_USE_POOLS is not set +CONFIG_NET_MEM_SIZE=153600 + +# +# LWIP Task Configurations +# +# CONFIG_NET_TCPIP_CORE_LOCKING is not set +# CONFIG_NET_TCPIP_CORE_LOCKING_INPUT is not set +CONFIG_NET_TCPIP_THREAD_NAME="LWIP_TCP/IP" +CONFIG_NET_TCPIP_THREAD_PRIO=110 +CONFIG_NET_TCPIP_THREAD_STACKSIZE=4096 +CONFIG_NET_COMPAT_MUTEX=y +CONFIG_NET_SYS_LIGHTWEIGHT_PROT=y +CONFIG_NET_DEFAULT_THREAD_NAME="lwIP" +CONFIG_NET_DEFAULT_THREAD_PRIO=1 +CONFIG_NET_DEFAULT_THREAD_STACKSIZE=0 + +# +# Debug Options for Network +# +# CONFIG_NET_LWIP_ASSERT is not set +# CONFIG_NET_LWIP_ERROR is not set +# CONFIG_NET_LWIP_DEBUG is not set + +# +# Enable Statistics +# +CONFIG_NET_STATS=y +CONFIG_NET_STATS_DISPLAY=y +CONFIG_NET_LINK_STATS=y +CONFIG_NET_ETHARP_STATS=y +CONFIG_NET_IP_STATS=y +# CONFIG_NET_IPFRAG_STATS is not set +# CONFIG_NET_ICMP_STATS is not set +CONFIG_NET_UDP_STATS=y +CONFIG_NET_TCP_STATS=y +CONFIG_NET_MEM_STATS=y +CONFIG_NET_SYS_STATS=y +# CONFIG_NET_IPv6_STATS is not set +# CONFIG_NET_IPv6_ICMP_STATS is not set +# CONFIG_NET_IPv6_MLD_STATS is not set +# CONFIG_NET_IPv6_ND_STATS is not set +# CONFIG_NET_LWIP_VLAN is not set +CONFIG_NET_LWIP_LOOPBACK_INTERFACE=y +# CONFIG_NET_LWIP_SLIP_INTERFACE is not set +# CONFIG_NET_LWIP_PPP_SUPPORT is not set +# CONFIG_NET_LWIP_SNMP is not set + +# +# Interface Name +# +CONFIG_NET_ETH_IFNAME="en" +CONFIG_NET_LOOP_IFNAME="lo" +CONFIG_NET_STA_IFNAME="wl" +CONFIG_NET_SOFTAP_IFNAME="sa" +CONFIG_NET_LWIP_NETDB=y +CONFIG_NET_DNS_TABLE_SIZE=4 +CONFIG_NET_DNS_MAX_NAME_LENGTH=256 +CONFIG_NET_DNS_MAX_SERVERS=2 +# CONFIG_NET_DNS_DOES_NAME_CHECK is not set +CONFIG_NET_DNS_SECURE=0 +# CONFIG_NET_DNS_LOCAL_HOSTLIST is not set + +# +# Driver buffer configuration +# +CONFIG_NET_MULTIBUFFER=y +CONFIG_NET_ETH_MTU=590 +CONFIG_NET_GUARDSIZE=2 + +# +# Data link support +# +# CONFIG_NET_MULTILINK is not set +CONFIG_NET_ETHERNET=y + +# +# Network Device Operations +# +# CONFIG_NETDEV_PHY_IOCTL is not set + +# +# Protocols +# +CONFIG_NETUTILS_DHCPD=y +CONFIG_NETUTILS_DHCPD_IGNOREBROADCAST=y +CONFIG_NETUTILS_DHCPD_INTERFACE="wl1" +CONFIG_NETUTILS_DHCPD_LEASETIME=864000 +CONFIG_NETUTILS_DHCPD_MINLEASETIME=86400 +CONFIG_NETUTILS_DHCPD_MAXLEASETIME=2592000 +CONFIG_NETUTILS_DHCPD_MAXLEASES=6 +CONFIG_NETUTILS_DHCPD_STARTIP=0xc0a82f02 +CONFIG_NETUTILS_DHCPD_ROUTERIP=0xc0a82f01 +CONFIG_NETUTILS_DHCPD_NETMASK=0xffffff00 +CONFIG_NETUTILS_DHCPD_DNSIP=0x08080808 +CONFIG_NETUTILS_DHCPD_OFFERTIME=3600 +CONFIG_NETUTILS_DHCPD_DECLINETIME=3600 +# CONFIG_NETUTILS_XMLRPC is not set +# CONFIG_NETUTILS_NTPCLIENT is not set +# CONFIG_NETUTILS_WEBSERVER is not set +# CONFIG_NETUTILS_FTPC is not set +# CONFIG_NETUTILS_MDNS is not set +# CONFIG_NETUTILS_FTPD is not set +CONFIG_NETUTILS_DHCPC=y +# CONFIG_NETUTILS_WEBSOCKET is not set +# CONFIG_NETUTILS_LIBCOAP is not set +# CONFIG_NETUTILS_TFTPC is not set +# CONFIG_NETUTILS_TELNETD is not set +# CONFIG_NETUTILS_SMTP is not set +# CONFIG_NETUTILS_MQTT is not set +CONFIG_NET_SECURITY_TLS=y +CONFIG_TLS_MPI_MAX_SIZE=512 + +# +# Wireless +# +CONFIG_WIFI_MANAGER=y +CONFIG_SELECT_WPA_SUPPLICANT=y +# CONFIG_SELECT_PROPIETARY_SUPPLICANT is not set +# CONFIG_SELECT_NO_DRIVER is not set +CONFIG_SELECT_SCSC_WLAN=y +# CONFIG_SELECT_PROPIETARY_WLAN is not set +CONFIG_NETUTILS_WIFI=y +CONFIG_SLSI_WIFI_DEFAULT_WLAN_COUNTRY_CODE="00" +CONFIG_SLSI_WIFI_DEFAULT_WLAN_TX_POWER=30 +# CONFIG_SLSI_WIFI_FILESYSTEM_SUPPORT is not set + +# +# wpa_supplicant +# +CONFIG_WPA_SUPPLICANT=y +CONFIG_WPA_SUPPLICANT_PRIORITY=100 +CONFIG_WPA_SUPPLICANT_STACKSIZE=16384 +CONFIG_WPA_SUPPLICANT_ENTRYPOINT="wpa_supplicant_main" +CONFIG_CTRL_IFACE=y +CONFIG_CTRL_IFACE_FIFO=y +CONFIG_WPA_CTRL_FIFO_DEV_REQ="/dev/wpa_ctrl_req" +CONFIG_WPA_CTRL_FIFO_DEV_CFM="/dev/wpa_ctrl_cfm" +CONFIG_WPA_CTRL_FIFO_DEV_GLOBAL_REQ="/dev/wpa_ctrl_global_req" +CONFIG_WPA_CTRL_FIFO_DEV_GLOBAL_CFM="/dev/wpa_ctrl_global_cfm" +CONFIG_WPA_MONITOR_FIFO_DEV="/dev/wpa_monitor" +CONFIG_WPA_CTRL_FIFO_MK_MODE=666 +CONFIG_ELOOP_POLL=y +# CONFIG_WPA_SUPPLICANT_CMD is not set +CONFIG_DRIVER_T20=y +# CONFIG_ENABLE_EAP_FOR_SUPPLICANT is not set +CONFIG_WIFIMGR_SOFTAP_IFNAME="wl1" +CONFIG_WIFIMGR_STA_IFNAME="wl1" +# CONFIG_WIFIMGR_DISABLE_AUTO_GET_IP is not set +# CONFIG_DISABLE_EXTERNAL_AUTOCONNECT is not set + +# +# Network utilities +# +CONFIG_NETUTILS_NETLIB=y +CONFIG_NET_NETMON=y + +# +# Audio Support +# +# CONFIG_AUDIO is not set + +# +# Media Support +# + +# +# File Systems +# +# CONFIG_DISABLE_MOUNTPOINT is not set +# CONFIG_DISABLE_PSEUDOFS_OPERATIONS is not set +CONFIG_FS_READABLE=y +CONFIG_FS_WRITABLE=y +# CONFIG_FS_AIO is not set +# CONFIG_FS_NAMED_SEMAPHORES is not set +CONFIG_FS_MQUEUE_MPATH="/var/mqueue" +CONFIG_FS_SMARTFS=y + +# +# SMARTFS options +# +CONFIG_SMARTFS_ERASEDSTATE=0xff +CONFIG_SMARTFS_MAXNAMLEN=32 +# CONFIG_SMARTFS_MULTI_ROOT_DIRS is not set +CONFIG_SMARTFS_ALIGNED_ACCESS=y +# CONFIG_SMARTFS_BAD_SECTOR is not set +# CONFIG_SMARTFS_DYNAMIC_HEADER is not set +# CONFIG_SMARTFS_JOURNALING is not set +# CONFIG_SMARTFS_SECTOR_RECOVERY is not set +CONFIG_FS_PROCFS=y +# CONFIG_FS_AUTOMOUNT_PROCFS is not set + +# +# Exclude individual procfs entries +# +# CONFIG_FS_PROCFS_EXCLUDE_PROCESS is not set +# CONFIG_FS_PROCFS_EXCLUDE_UPTIME is not set +# CONFIG_FS_PROCFS_EXCLUDE_VERSION is not set +# CONFIG_FS_PROCFS_EXCLUDE_MTD is not set +# CONFIG_FS_PROCFS_EXCLUDE_PARTITIONS is not set +# CONFIG_FS_PROCFS_EXCLUDE_SMARTFS is not set +# CONFIG_FS_PROCFS_EXCLUDE_POWER is not set +CONFIG_FS_ROMFS=y +# CONFIG_FS_TMPFS is not set + +# +# Block Driver Configurations +# +CONFIG_RAMDISK=y + +# +# MTD Configuration +# +CONFIG_MTD=y +CONFIG_MTD_PARTITION=y +CONFIG_MTD_PARTITION_NAMES=y +CONFIG_MTD_PROGMEM=y +CONFIG_MTD_FTL=y + +# +# MTD_FTL Configurations +# +CONFIG_MTD_CONFIG=y + +# +# MTD Configurations +# +# CONFIG_MTD_CONFIG_RAM_CONSOLIDATE is not set +CONFIG_MTD_CONFIG_ERASEDVALUE=0xff +# CONFIG_MTD_BYTE_WRITE is not set + +# +# MTD Device Drivers +# +# CONFIG_MTD_M25P is not set +# CONFIG_RAMMTD is not set +CONFIG_MTD_SMART=y + +# +# SMART Device options +# +CONFIG_MTD_SMART_SECTOR_SIZE=512 +# CONFIG_MTD_SMART_WEAR_LEVEL is not set +# CONFIG_MTD_SMART_ENABLE_CRC is not set +# CONFIG_MTD_SMART_SECTOR_ERASE_DEBUG is not set +# CONFIG_MTD_SMART_ALLOC_DEBUG is not set +# CONFIG_MTD_W25 is not set + +# +# System Logging +# +# CONFIG_SYSLOG is not set +# CONFIG_SYSLOG_TIMESTAMP is not set + +# +# Database +# +# CONFIG_ARASTORAGE is not set + +# +# Memory Management +# +# CONFIG_REALLOC_DISABLE_NEIGHBOR_EXTENSION is not set +# CONFIG_MM_SMALL is not set +CONFIG_MM_REGIONS=1 +# CONFIG_GRAN is not set + +# +# Power Management +# +CONFIG_PM=y +# CONFIG_DEBUG_PM is not set +# CONFIG_PM_TEST is not set +CONFIG_PM_DEVNAME_LEN=32 +# CONFIG_PM_METRICS is not set +CONFIG_PM_SLICEMS=100 +CONFIG_PM_NDOMAINS=1 +CONFIG_PM_MEMORY=2 +CONFIG_PM_COEFN=1 +CONFIG_PM_COEF1=1 +CONFIG_PM_COEF2=1 +CONFIG_PM_COEF3=1 +CONFIG_PM_COEF4=1 +CONFIG_PM_COEF5=1 +CONFIG_PM_IDLEENTER_THRESH=1 +CONFIG_PM_IDLEEXIT_THRESH=2 +CONFIG_PM_IDLEENTER_COUNT=30 +CONFIG_PM_STANDBYENTER_THRESH=1 +CONFIG_PM_STANDBYEXIT_THRESH=2 +CONFIG_PM_STANDBYENTER_COUNT=50 +CONFIG_PM_SLEEPENTER_THRESH=1 +CONFIG_PM_SLEEPEXIT_THRESH=2 +CONFIG_PM_SLEEPENTER_COUNT=70 + +# +# Debug Options +# +CONFIG_DEBUG=y +CONFIG_DEBUG_ERROR=y +# CONFIG_DEBUG_WARN is not set +CONFIG_DEBUG_VERBOSE=y + +# +# Subsystem Debug Options +# +# CONFIG_DEBUG_LIB is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_DEBUG_IOTBUS is not set +# CONFIG_DEBUG_MM is not set +CONFIG_DEBUG_NET=y +# CONFIG_DEBUG_NET_ERROR is not set +# CONFIG_DEBUG_NET_INFO is not set +# CONFIG_DEBUG_SCHED is not set +# CONFIG_DEBUG_TASH is not set +CONFIG_DEBUG_WLAN=y + +# +# SLSI WLAN FW Debug Options +# +# CONFIG_SCSC_ENABLE_FWFAULT_LOG is not set + +# +# SLSI WLAN Driver Debug Options +# +CONFIG_DEBUG_WLAN_DRIVER_ERROR=y +# CONFIG_DEBUG_WLAN_DRIVER_DEBUG is not set +# CONFIG_DEBUG_WLAN_DRIVER_MORE is not set +# CONFIG_DEBUG_WLAN_DRIVER_INFO is not set + +# +# SLSI WPA Supplicant Debug Options +# +CONFIG_DEBUG_WLAN_SUPPLICANT_ERROR=y +# CONFIG_DEBUG_WLAN_SUPPLICANT_DEBUG is not set +# CONFIG_DEBUG_WLAN_SUPPLICANT_MORE is not set +# CONFIG_DEBUG_WLAN_SUPPLICANT_INFO is not set + +# +# SLSI Wi-Fi API Debug Options +# +CONFIG_DEBUG_WLAN_API_ERROR=y +# CONFIG_DEBUG_WLAN_API_DEBUG is not set +# CONFIG_DEBUG_WLAN_API_INFO is not set + +# +# OS Function Debug Options +# +# CONFIG_ARCH_HAVE_HEAPCHECK is not set +CONFIG_DEBUG_MM_HEAPINFO=y +# CONFIG_DEBUG_IRQ is not set + +# +# Driver Debug Options +# +# CONFIG_DEBUG_I2S is not set +# CONFIG_DEBUG_PWM is not set +# CONFIG_DEBUG_RTC is not set +# CONFIG_DEBUG_SPI is not set +# CONFIG_DEBUG_WATCHDOG is not set + +# +# System Debug Options +# +# CONFIG_DEBUG_SYSTEM is not set + +# +# Stack Debug Options +# +CONFIG_ARCH_HAVE_STACKCHECK=y +CONFIG_STACK_COLORATION=y + +# +# Build Debug Options +# +CONFIG_DEBUG_SYMBOLS=y +# CONFIG_FRAME_POINTER is not set + +# +# Logger Module +# +CONFIG_LOGM=y +# CONFIG_PRINTF2LOGM is not set +CONFIG_SYSLOG2LOGM=y +# CONFIG_LOGM_TIMESTAMP is not set +CONFIG_LOGM_BUFFER_SIZE=10240 +CONFIG_LOGM_PRINT_INTERVAL=1000 +CONFIG_LOGM_TASK_PRIORITY=110 +CONFIG_LOGM_TASK_STACKSIZE=2048 +# CONFIG_LOGM_TEST is not set + +# +# Built-in Libraries +# + +# +# Standard C Library Options +# +CONFIG_STDIO_BUFFER_SIZE=64 +CONFIG_STDIO_LINEBUFFER=y +CONFIG_NUNGET_CHARS=2 +CONFIG_LIB_HOMEDIR="/" +CONFIG_LIBM=y +# CONFIG_NOPRINTF_FIELDWIDTH is not set +CONFIG_LIBC_FLOATINGPOINT=y +CONFIG_LIBC_FLOATPRECISION=6 +CONFIG_LIBC_SCANSET=y +# CONFIG_NOPRINTF_LONGLONG_TO_ASCII is not set +CONFIG_LIBC_IOCTL_VARIADIC=y +# CONFIG_LIBC_WCHAR is not set +# CONFIG_LIBC_LOCALE is not set +CONFIG_LIB_RAND_ORDER=1 +# CONFIG_EOL_IS_CR is not set +# CONFIG_EOL_IS_LF is not set +# CONFIG_EOL_IS_BOTH_CRLF is not set +CONFIG_EOL_IS_EITHER_CRLF=y +CONFIG_LIBC_STRERROR=y +# CONFIG_LIBC_STRERROR_SHORT is not set +# CONFIG_LIBC_PERROR_STDOUT is not set +CONFIG_LIBC_TMPDIR="/tmp" +CONFIG_LIBC_MAX_TMPFILE=32 +CONFIG_ARCH_LOWPUTC=y +# CONFIG_LIBC_LOCALTIME is not set +# CONFIG_TIME_EXTENDED is not set +CONFIG_LIB_SENDFILE_BUFSIZE=512 +CONFIG_ARCH_OPTIMIZED_FUNCTIONS=y +# CONFIG_ARCH_MEMCPY is not set +CONFIG_MEMCPY_VIK=y +# CONFIG_MEMCPY_PRE_INC_PTRS is not set +CONFIG_MEMCPY_INDEXED_COPY=y +# CONFIG_MEMCPY_64BIT is not set +# CONFIG_ARCH_MEMCMP is not set +# CONFIG_ARCH_MEMMOVE is not set +# CONFIG_ARCH_MEMSET is not set +# CONFIG_MEMSET_OPTSPEED is not set +# CONFIG_ARCH_STRCHR is not set +# CONFIG_ARCH_STRCMP is not set +# CONFIG_ARCH_STRCPY is not set +# CONFIG_ARCH_STRNCPY is not set +# CONFIG_ARCH_STRLEN is not set +# CONFIG_ARCH_STRNLEN is not set +# CONFIG_ARCH_BZERO is not set + +# +# Non-standard Library Support +# + +# +# Basic CXX Support +# +# CONFIG_C99_BOOL8 is not set +# CONFIG_HAVE_CXX is not set + +# +# External Libraries +# +# CONFIG_AVS_DEVICE_SDK is not set +# CONFIG_AWS_SDK is not set +# CONFIG_NETUTILS_CODECS is not set + +# +# CURL Options +# +# CONFIG_ENABLE_CURL is not set +# CONFIG_ERROR_REPORT is not set +# CONFIG_ENABLE_IOTIVITY is not set +CONFIG_NETUTILS_JSON=y +# CONFIG_LIBTUV is not set +# CONFIG_LWM2M_WAKAAMA is not set +# CONFIG_STRESS_TOOL is not set +# CONFIG_VOICE_SOFTWARE_EPD is not set + +# +# Application Configuration +# + +# +# Application entry point list +# +# CONFIG_ENTRY_MANUAL is not set +# CONFIG_ENTRY_HELLO is not set +CONFIG_ENTRY_IOTJS_STARTUP=y +CONFIG_USER_ENTRYPOINT="iotjs_startup_main" +CONFIG_BUILTIN_APPS=y + +# +# Examples +# +# CONFIG_EXAMPLES_AVS_TEST is not set +# CONFIG_EXAMPLES_AWS is not set +# CONFIG_EXAMPLES_CURLTEST is not set +# CONFIG_EXAMPLES_DNSCLIENT_TEST is not set +# CONFIG_EXAMPLES_DTLS_CLIENT is not set +# CONFIG_EXAMPLES_DTLS_SERVER is not set +# CONFIG_EXAMPLES_EEPROM_TEST is not set +# CONFIG_EXAMPLES_EVENTLOOP is not set +# CONFIG_EXAMPLES_FOTA_SAMPLE is not set +# CONFIG_FILESYSTEM_HELPER_ENABLE is not set +CONFIG_EXAMPLES_HELLO=y +# CONFIG_EXAMPLES_HELLOXX is not set +# CONFIG_EXAMPLES_IOTBUS_TEST is not set +CONFIG_EXAMPLES_IOTJS_STARTUP=y +CONFIG_EXAMPLES_IOTJS_STARTUP_JS_FILE="/rom/example/index.js" +# CONFIG_EXAMPLES_IOTJS_STARTUP_WIFI is not set +# CONFIG_EXAMPLES_KERNEL_SAMPLE is not set +# CONFIG_EXAMPLES_LIBTUV is not set +# CONFIG_EXAMPLES_NETTEST is not set +# CONFIG_EXAMPLES_PROC_TEST is not set +# CONFIG_EXAMPLES_SELECT_TEST is not set +# CONFIG_EXAMPLES_SENSORBOARD is not set +# CONFIG_EXAMPLES_SETJMP_TEST is not set +CONFIG_EXAMPLES_SLSIWIFI=y +CONFIG_EXAMPLES_SLSIWIFI_PRIORITY=50 +CONFIG_EXAMPLES_SLSIWIFI_STACKSIZE=2048 +# CONFIG_EXAMPLES_SMART is not set +# CONFIG_EXAMPLES_SMART_TEST is not set +# CONFIG_EXAMPLES_SPEECH_DETECTOR_TEST is not set +# CONFIG_EXAMPLES_ST_THINGS is not set +# CONFIG_EXAMPLES_TESTCASE is not set +# CONFIG_EXAMPLES_TLS_BENCHMARK is not set +# CONFIG_EXAMPLES_TLS_CLIENT is not set +# CONFIG_EXAMPLES_TLS_SELFTEST is not set +# CONFIG_EXAMPLES_TLS_SERVER is not set +# CONFIG_EXAMPLES_WIFIMANAGER_TEST is not set + +# +# Platform-specific Support +# +# CONFIG_PLATFORM_CONFIGDATA is not set + +# +# Shell +# +CONFIG_TASH=y +CONFIG_TASH_MAX_COMMANDS=132 +# CONFIG_TASH_USLEEP is not set +CONFIG_TASH_COMMAND_INTERFACE=y +CONFIG_TASH_CMDTASK_STACKSIZE=4096 +CONFIG_TASH_CMDTASK_PRIORITY=100 +# CONFIG_TASH_SCRIPT is not set + +# +# System Libraries and Add-Ons +# +# CONFIG_SYSTEM_CLE is not set +# CONFIG_SYSTEM_CUTERM is not set +# CONFIG_SYSTEM_FLASH_ERASEALL is not set +# CONFIG_SYSTEM_FOTA_HAL is not set +# CONFIG_SYSTEM_I2CTOOL is not set +# CONFIG_SYSTEM_INIFILE is not set +CONFIG_SYSTEM_PREAPP_INIT=y +CONFIG_SYSTEM_PREAPP_STACKSIZE=2048 +# CONFIG_SYSTEM_INSTALL is not set +CONFIG_SYSTEM_IPERF=y +# CONFIG_SYSTEM_NETDB is not set +CONFIG_SYSTEM_RAMTEST=y +CONFIG_SYSTEM_RAMTEST_PRIORITY=100 +CONFIG_SYSTEM_RAMTEST_STACKSIZE=1024 +CONFIG_SYSTEM_READLINE=y +CONFIG_READLINE_ECHO=y +CONFIG_SYSTEM_INFORMATION=y +CONFIG_KERNEL_CMDS=y +CONFIG_FS_CMDS=y +CONFIG_FSCMD_BUFFER_LEN=64 +CONFIG_NET_CMDS=y +CONFIG_NET_PING_CMD=y +CONFIG_NET_PING_CMD_ICOUNT=5 +CONFIG_ENABLE_DATE_CMD=y +CONFIG_ENABLE_ENV_GET_CMD=y +CONFIG_ENABLE_ENV_SET_CMD=y +CONFIG_ENABLE_ENV_UNSET_CMD=y +CONFIG_ENABLE_FREE_CMD=y +CONFIG_ENABLE_HEAPINFO_CMD=y +# CONFIG_HEAPINFO_USER_GROUP is not set +# CONFIG_ENABLE_IRQINFO_CMD is not set +CONFIG_ENABLE_KILL_CMD=y +CONFIG_ENABLE_KILLALL_CMD=y +CONFIG_ENABLE_PS_CMD=y +CONFIG_ENABLE_STACKMONITOR_CMD=y +CONFIG_STACKMONITOR_PRIORITY=100 +CONFIG_STACKMONITOR_INTERVAL=5 +CONFIG_ENABLE_UPTIME_CMD=y +# CONFIG_SYSTEM_VI is not set + +# +# Runtime Environment +# +CONFIG_ENABLE_IOTJS=y +CONFIG_IOTJS_PRIORITY=100 +CONFIG_IOTJS_STACKSIZE=32768 +CONFIG_IOTJS_JERRY_HEAP=128 + +# +# Device Management +# +# CONFIG_DM is not set + +# +# Task manager +# +# CONFIG_TASK_MANAGER is not set + +# +# Event Loop Framework +# +# CONFIG_EVENTLOOP is not set + +# +# Things Management +# +# CONFIG_ST_THINGS is not set + +# +# IoTBus Framework +# +CONFIG_IOTBUS=y +CONFIG_IOTBUS_GPIO=y +CONFIG_IOTBUS_I2C=y +CONFIG_IOTBUS_PWM=y +CONFIG_IOTBUS_SPI=y +CONFIG_IOTBUS_UART=y diff --git a/config/tizenrt/artik05x/configs/release/defconfig b/config/tizenrt/artik05x/configs/release/defconfig new file mode 100644 index 0000000000..2e6189f46f --- /dev/null +++ b/config/tizenrt/artik05x/configs/release/defconfig @@ -0,0 +1,1308 @@ +# +# Automatically generated file; DO NOT EDIT. +# TinyAra Configuration +# + +# +# Build Setup +# +# CONFIG_EXPERIMENTAL is not set +# CONFIG_DEFAULT_SMALL is not set +CONFIG_HOST_LINUX=y +# CONFIG_HOST_OSX is not set +# CONFIG_HOST_WINDOWS is not set +# CONFIG_HOST_OTHER is not set +# CONFIG_WINDOWS_NATIVE is not set + +# +# Build Configuration +# +CONFIG_APPS_DIR="../apps" +CONFIG_FRAMEWORK_DIR="../framework" +CONFIG_TOOLS_DIR="../tools" +CONFIG_BUILD_FLAT=y +# CONFIG_BUILD_PROTECTED is not set +# CONFIG_BUILD_2PASS is not set + +# +# Binary Output Formats +# +# CONFIG_INTELHEX_BINARY is not set +# CONFIG_MOTOROLA_SREC is not set +CONFIG_RAW_BINARY=y +# CONFIG_UBOOT_UIMAGE is not set +# CONFIG_DOWNLOAD_IMAGE is not set +# CONFIG_SMARTFS_IMAGE is not set + +# +# Customize Header Files +# +# CONFIG_ARCH_STDINT_H is not set +# CONFIG_ARCH_STDBOOL_H is not set +# CONFIG_ARCH_MATH_H is not set +# CONFIG_ARCH_FLOAT_H is not set +# CONFIG_ARCH_STDARG_H is not set +CONFIG_ARCH_HAVE_CUSTOMOPT=y +# CONFIG_DEBUG_NOOPT is not set +# CONFIG_DEBUG_CUSTOMOPT is not set +# CONFIG_DEBUG_FULLOPT is not set + +# +# Hardware Configuration +# + +# +# Chip Selection +# +CONFIG_ARCH_ARM=y +CONFIG_ARCH="arm" +# CONFIG_ARCH_CHIP_LM is not set +CONFIG_ARCH_CHIP_S5J=y +# CONFIG_ARCH_CHIP_BCM4390X is not set +CONFIG_ARCH_CHIP="s5j" + +# +# ARM Options +# +# CONFIG_ARCH_CORTEXM3 is not set +# CONFIG_ARCH_CORTEXM4 is not set +CONFIG_ARCH_CORTEXR4=y +CONFIG_ARCH_FAMILY="armv7-r" +# CONFIG_ARCH_HAVE_FPU is not set +CONFIG_ARMV7M_MPU=y +CONFIG_ARMV7M_MPU_NREGIONS=12 + +# +# Exception stack options +# +CONFIG_ARCH_HAVE_DABORTSTACK=y +CONFIG_ARCH_DABORTSTACK=0 + +# +# ARMv7-R Configuration Options +# +CONFIG_ARMV7R_HAVE_GICv2=y +CONFIG_ARMV7R_MEMINIT=y +CONFIG_ARMV7R_ICACHE=y +CONFIG_ARMV7R_DCACHE=y +# CONFIG_ARMV7R_DCACHE_WRITETHROUGH is not set +# CONFIG_ARMV7R_HAVE_L2CC is not set +# CONFIG_ARMV7R_HAVE_L2CC_PL310 is not set +# CONFIG_ARMV7R_TOOLCHAIN_BUILDROOT is not set +# CONFIG_ARMV7R_TOOLCHAIN_CODESOURCERYL is not set +CONFIG_ARMV7R_TOOLCHAIN_GNU_EABIL=y +# CONFIG_ARMV7R_TOOLCHAIN_GNU_OABI is not set +# CONFIG_ARMV7R_HAVE_DECODEFIQ is not set + +# +# S5J Configuration Options +# +CONFIG_ARCH_CHIP_S5JT200=y +CONFIG_S5J_S5JT200=y + +# +# S5J Peripheral Support +# +CONFIG_S5J_HAVE_ADC=y +CONFIG_S5J_HAVE_DMA=y +CONFIG_S5J_HAVE_I2C=y +CONFIG_S5J_HAVE_I2S=y +CONFIG_S5J_HAVE_MCT=y +CONFIG_S5J_HAVE_PWM0=y +CONFIG_S5J_HAVE_PWM1=y +CONFIG_S5J_HAVE_PWM2=y +CONFIG_S5J_HAVE_PWM3=y +CONFIG_S5J_HAVE_PWM4=y +CONFIG_S5J_HAVE_PWM5=y +CONFIG_S5J_HAVE_RTC=y +CONFIG_S5J_HAVE_SFLASH=y +CONFIG_S5J_HAVE_SPI=y +CONFIG_S5J_HAVE_SSS=y +CONFIG_S5J_HAVE_UART0=y +CONFIG_S5J_HAVE_UART1=y +CONFIG_S5J_HAVE_UART2=y +CONFIG_S5J_HAVE_UART3=y +CONFIG_S5J_HAVE_UART4=y +CONFIG_S5J_HAVE_WATCHDOG=y +CONFIG_S5J_ADC=y +# CONFIG_S5J_DMA is not set +CONFIG_S5J_I2C=y +# CONFIG_S5J_I2S is not set +CONFIG_S5J_MCT=y +CONFIG_S5J_TIMER0=y +# CONFIG_S5J_TIMER1 is not set +# CONFIG_S5J_TIMER2 is not set +# CONFIG_S5J_TIMER3 is not set +# CONFIG_S5J_UART_FLOWCONTROL is not set +CONFIG_S5J_UART0=y +CONFIG_S5J_UART1=y +CONFIG_S5J_UART2=y +CONFIG_S5J_UART3=y +CONFIG_S5J_UART4=y +CONFIG_S5J_PWM=y +CONFIG_S5J_PWM0=y +CONFIG_S5J_PWM1=y +CONFIG_S5J_PWM2=y +CONFIG_S5J_PWM3=y +CONFIG_S5J_PWM4=y +CONFIG_S5J_PWM5=y +# CONFIG_S5J_SSS is not set +CONFIG_S5J_SPI=y +# CONFIG_S5J_WATCHDOG is not set +CONFIG_S5J_SFLASH=y +# CONFIG_S5J_SENSOR_PPD42NS is not set + +# +# Architecture Options +# +# CONFIG_ARCH_NOINTC is not set +# CONFIG_ARCH_VECNOTIRQ is not set +# CONFIG_ARCH_DMA is not set +# CONFIG_ARCH_HAVE_IRQPRIO is not set +# CONFIG_ARCH_L2CACHE is not set +# CONFIG_ARCH_HAVE_COHERENT_DCACHE is not set +# CONFIG_ARCH_HAVE_ADDRENV is not set +# CONFIG_ARCH_NEED_ADDRENV_MAPPING is not set +CONFIG_ARCH_HAVE_VFORK=y +# CONFIG_ARCH_HAVE_MMU is not set +CONFIG_ARCH_HAVE_MPU=y +# CONFIG_ARCH_NAND_HWECC is not set +# CONFIG_ARCH_HAVE_EXTCLK is not set +# CONFIG_ARCH_HAVE_POWEROFF is not set +CONFIG_ARCH_HAVE_RESET=y +CONFIG_ARCH_USE_MPU=y +CONFIG_ARCH_STACKDUMP=y +# CONFIG_DEBUG_DISPLAY_SYMBOL is not set +# CONFIG_ENDIAN_BIG is not set +# CONFIG_ARCH_IDLE_CUSTOM is not set +CONFIG_ARCH_CUSTOM_PMINIT=y +# CONFIG_ARCH_HAVE_RAMFUNCS is not set +# CONFIG_ARCH_HAVE_RAMVECTORS is not set + +# +# Board Settings +# +CONFIG_BOARD_LOOPSPERMSEC=29100 +# CONFIG_ARCH_CALIBRATION is not set + +# +# Interrupt options +# +CONFIG_ARCH_HAVE_INTERRUPTSTACK=y +CONFIG_ARCH_INTERRUPTSTACK=0 +# CONFIG_ARCH_HAVE_HIPRI_INTERRUPT is not set + +# +# Boot options +# +# CONFIG_BOOT_RUNFROMEXTSRAM is not set +CONFIG_BOOT_RUNFROMFLASH=y +# CONFIG_BOOT_RUNFROMISRAM is not set +# CONFIG_BOOT_RUNFROMSDRAM is not set +# CONFIG_BOOT_COPYTORAM is not set + +# +# Boot Memory Configuration +# +CONFIG_RAM_START=0x02023800 +CONFIG_RAM_SIZE=968704 +# CONFIG_DDR is not set +# CONFIG_ARCH_HAVE_SDRAM is not set + +# +# Board Selection +# +CONFIG_ARCH_BOARD_ARTIK053=y +# CONFIG_ARCH_BOARD_ARTIK053S is not set +# CONFIG_ARCH_BOARD_ARTIK055S is not set +# CONFIG_ARCH_BOARD_SIDK_S5JT200 is not set +CONFIG_ARCH_BOARD_ARTIK05X_FAMILY=y +CONFIG_ARCH_BOARD="artik05x" + +# +# Common Board Options +# +# CONFIG_BOARD_CRASHDUMP is not set +# CONFIG_BOARD_ASSERT_AUTORESET is not set +CONFIG_LIB_BOARDCTL=y +CONFIG_BOARDCTL_RESET=y +# CONFIG_BOARDCTL_UNIQUEID is not set +# CONFIG_BOARD_FOTA_SUPPORT is not set + +# +# Board-Specific Options +# +CONFIG_ARTIK05X_BOOT_FAILURE_DETECTION=y +CONFIG_ARTIK05X_BOOT_COUNTS_ADDR=0x80090810 +CONFIG_ARTIK05X_FLASH_CAPACITY=8388608 +CONFIG_ARTIK05X_FLASH_PAGE_SIZE=4096 +CONFIG_ARTIK05X_FLASH_PART=y +CONFIG_ARTIK05X_FLASH_MINOR=0 +CONFIG_ARTIK05X_FLASH_PART_LIST="16,48,192,32,512,2400,1536,1536,1000,400,8,512," +CONFIG_ARTIK05X_FLASH_PART_TYPE="none,ftl,none,none,none,none,none,ftl,smartfs,romfs,config,none," +CONFIG_ARTIK05X_FLASH_PART_NAME="bl1,sssro,bl2,sssfw,wlanfw,os,factory,ota,user,rom,nvram,sssrw," +CONFIG_ARTIK05X_AUTOMOUNT=y +CONFIG_ARTIK05X_AUTOMOUNT_USERFS=y +CONFIG_ARTIK05X_AUTOMOUNT_USERFS_DEVNAME="/dev/smart0p8" +CONFIG_ARTIK05X_AUTOMOUNT_USERFS_MOUNTPOINT="/mnt" +# CONFIG_ARTIK05X_AUTOMOUNT_SSSRW is not set +CONFIG_ARTIK05X_AUTOMOUNT_ROMFS=y +CONFIG_ARTIK05X_AUTOMOUNT_ROMFS_DEVNAME="/dev/mtdblock9" +CONFIG_ARTIK05X_AUTOMOUNT_ROMFS_MOUNTPOINT="/rom" + +# +# Kernel Features +# +CONFIG_DISABLE_OS_API=y +# CONFIG_DISABLE_POSIX_TIMERS is not set +# CONFIG_DISABLE_PTHREAD is not set +# CONFIG_DISABLE_SIGNALS is not set +# CONFIG_DISABLE_MQUEUE is not set +# CONFIG_DISABLE_ENVIRON is not set + +# +# Clocks and Timers +# +CONFIG_ARCH_HAVE_TICKLESS=y +# CONFIG_SCHED_TICKLESS is not set +CONFIG_USEC_PER_TICK=9979 +CONFIG_SYSTEM_TIME64=y +CONFIG_CLOCK_MONOTONIC=y +# CONFIG_JULIAN_TIME is not set +CONFIG_MAX_WDOGPARMS=4 +CONFIG_PREALLOC_WDOGS=32 +CONFIG_WDOG_INTRESERVE=4 +CONFIG_PREALLOC_TIMERS=8 + +# +# Tasks and Scheduling +# +CONFIG_INIT_ENTRYPOINT=y +CONFIG_RR_INTERVAL=100 +CONFIG_TASK_NAME_SIZE=31 +CONFIG_MAX_TASKS=32 +CONFIG_SCHED_HAVE_PARENT=y +# CONFIG_SCHED_CHILD_STATUS is not set +CONFIG_SCHED_WAITPID=y + +# +# Pthread Options +# +CONFIG_PTHREAD_MUTEX_TYPES=y +# CONFIG_PTHREAD_MUTEX_ROBUST is not set +CONFIG_PTHREAD_MUTEX_UNSAFE=y +# CONFIG_PTHREAD_MUTEX_BOTH is not set +CONFIG_NPTHREAD_KEYS=4 +CONFIG_NPTHREAD_DESTRUCTOR_ITERATIONS=4 +# CONFIG_PTHREAD_CLEANUP is not set +# CONFIG_CANCELLATION_POINTS is not set + +# +# Performance Monitoring +# +# CONFIG_SCHED_CPULOAD is not set + +# +# Latency optimization +# +# CONFIG_SCHED_YIELD_OPTIMIZATION is not set + +# +# Files and I/O +# +CONFIG_DEV_CONSOLE=y +# CONFIG_FDCLONE_DISABLE is not set +# CONFIG_FDCLONE_STDIO is not set +# CONFIG_SDCLONE_DISABLE is not set +CONFIG_NFILE_DESCRIPTORS=16 +CONFIG_NFILE_STREAMS=16 +CONFIG_NAME_MAX=32 +CONFIG_PRIORITY_INHERITANCE=y +CONFIG_SEM_PREALLOCHOLDERS=16 +CONFIG_SEM_NNESTPRIO=16 + +# +# RTOS hooks +# +CONFIG_BOARD_INITIALIZE=y +# CONFIG_BOARD_INITTHREAD is not set +# CONFIG_SCHED_STARTHOOK is not set +CONFIG_SCHED_ATEXIT=y +CONFIG_SCHED_ONEXIT=y + +# +# Signal Numbers +# +CONFIG_SIG_SIGUSR1=1 +CONFIG_SIG_SIGUSR2=2 +CONFIG_SIG_SIGALARM=3 +CONFIG_SIG_SIGCHLD=4 +CONFIG_SIG_SIGCONDTIMEDOUT=16 +CONFIG_SIG_SIGWORK=17 + +# +# POSIX Message Queue Options +# +CONFIG_PREALLOC_MQ_MSGS=4 +CONFIG_MQ_MAXMSGSIZE=600 + +# +# Work Queue Support +# +CONFIG_SCHED_WORKQUEUE=y +CONFIG_SCHED_WORKQUEUE_SORTING=y +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_HPWORKPRIORITY=224 +CONFIG_SCHED_HPWORKPERIOD=50000 +CONFIG_SCHED_HPWORKSTACKSIZE=2048 +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_LPNTHREADS=1 +CONFIG_SCHED_LPWORKPRIORITY=176 +CONFIG_SCHED_LPWORKPRIOMAX=176 +CONFIG_SCHED_LPWORKPERIOD=50000 +CONFIG_SCHED_LPWORKSTACKSIZE=2048 + +# +# Stack size information +# +CONFIG_IDLETHREAD_STACKSIZE=1024 +CONFIG_USERMAIN_STACKSIZE=2048 +# CONFIG_MPU_STACKGAURD is not set +CONFIG_PTHREAD_STACK_MIN=256 +CONFIG_PTHREAD_STACK_DEFAULT=2048 + +# +# Device Drivers +# +# CONFIG_DISABLE_POLL is not set +CONFIG_DEV_NULL=y +CONFIG_DEV_ZERO=y +# CONFIG_DRVR_WRITEBUFFER is not set +# CONFIG_DRVR_READAHEAD is not set +# CONFIG_CAN is not set +# CONFIG_ARCH_HAVE_PWM_PULSECOUNT is not set +# CONFIG_ARCH_HAVE_PWM_MULTICHAN is not set +CONFIG_PWM=y +# CONFIG_ARCH_HAVE_I2CRESET is not set +CONFIG_I2C=y +CONFIG_I2C_SLAVE=y +CONFIG_I2C_USERIO=y +CONFIG_I2C_TRANSFER=y +CONFIG_I2C_POLLED=y +# CONFIG_I2C_TRACE is not set +# CONFIG_I2C_WRITEREAD is not set +CONFIG_SPI=y +# CONFIG_SPI_OWNBUS is not set +CONFIG_SPI_EXCHANGE=y +# CONFIG_SPI_CMDDATA is not set +# CONFIG_SPI_BITBANG is not set +CONFIG_GPIO=y +# CONFIG_I2S is not set +# CONFIG_AUDIO_DEVICES is not set +CONFIG_BCH=y +CONFIG_RTC=y +CONFIG_RTC_DATETIME=y +# CONFIG_RTC_ALARM is not set +CONFIG_RTC_DRIVER=y +# CONFIG_RTC_IOCTL is not set +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_DEVPATH="/dev/watchdog0" +# CONFIG_TIMER is not set +CONFIG_ANALOG=y +CONFIG_ADC=y +CONFIG_ADC_FIFOSIZE=8 +# CONFIG_DAC is not set +CONFIG_NETDEVICES=y + +# +# General Ethernet MAC Driver Options +# +CONFIG_NETDEV_TELNET=y +CONFIG_NETDEV_MULTINIC=y +# CONFIG_NET_DUMPPACKET is not set + +# +# External Ethernet MAC Device Support +# +# CONFIG_NET_DM90x0 is not set +# CONFIG_ENC28J60 is not set +# CONFIG_ENCX24J600 is not set +# CONFIG_NET_E1000 is not set +# CONFIG_NET_SLIP is not set +# CONFIG_NET_VNET is not set +# CONFIG_PIPES is not set +CONFIG_POWER=y +# CONFIG_BATTERY_CHARGER is not set +# CONFIG_BATTERY_GAUGE is not set +CONFIG_SERIAL=y +# CONFIG_DEV_LOWCONSOLE is not set +# CONFIG_16550_UART is not set +# CONFIG_ARCH_HAVE_UART is not set +CONFIG_ARCH_HAVE_UART0=y +CONFIG_ARCH_HAVE_UART1=y +CONFIG_ARCH_HAVE_UART2=y +CONFIG_ARCH_HAVE_UART3=y +CONFIG_ARCH_HAVE_UART4=y +# CONFIG_ARCH_HAVE_UART5 is not set +# CONFIG_ARCH_HAVE_UART6 is not set +# CONFIG_ARCH_HAVE_UART7 is not set +# CONFIG_ARCH_HAVE_UART8 is not set +# CONFIG_ARCH_HAVE_SCI0 is not set +# CONFIG_ARCH_HAVE_SCI1 is not set +# CONFIG_ARCH_HAVE_USART0 is not set +# CONFIG_ARCH_HAVE_USART1 is not set +# CONFIG_ARCH_HAVE_USART2 is not set +# CONFIG_ARCH_HAVE_USART3 is not set +# CONFIG_ARCH_HAVE_USART4 is not set +# CONFIG_ARCH_HAVE_USART5 is not set +# CONFIG_ARCH_HAVE_USART6 is not set +# CONFIG_ARCH_HAVE_USART7 is not set +# CONFIG_ARCH_HAVE_USART8 is not set +# CONFIG_ARCH_HAVE_OTHER_UART is not set + +# +# USART Configuration +# +CONFIG_MCU_SERIAL=y +CONFIG_STANDARD_SERIAL=y +CONFIG_SERIAL_NPOLLWAITERS=2 +# CONFIG_SERIAL_IFLOWCONTROL is not set +# CONFIG_SERIAL_OFLOWCONTROL is not set +# CONFIG_SERIAL_TIOCSERGSTRUCT is not set +CONFIG_ARCH_HAVE_SERIAL_TERMIOS=y +CONFIG_SERIAL_TERMIOS=y +# CONFIG_UART0_SERIAL_CONSOLE is not set +# CONFIG_UART1_SERIAL_CONSOLE is not set +# CONFIG_UART2_SERIAL_CONSOLE is not set +# CONFIG_UART3_SERIAL_CONSOLE is not set +CONFIG_UART4_SERIAL_CONSOLE=y +# CONFIG_OTHER_SERIAL_CONSOLE is not set +# CONFIG_NO_SERIAL_CONSOLE is not set + +# +# UART0 Configuration +# +CONFIG_UART0_RXBUFSIZE=64 +CONFIG_UART0_TXBUFSIZE=64 +CONFIG_UART0_BAUD=115200 +CONFIG_UART0_BITS=8 +CONFIG_UART0_PARITY=0 +CONFIG_UART0_2STOP=0 +# CONFIG_UART0_IFLOWCONTROL is not set +# CONFIG_UART0_OFLOWCONTROL is not set + +# +# UART1 Configuration +# +CONFIG_UART1_RXBUFSIZE=256 +CONFIG_UART1_TXBUFSIZE=256 +CONFIG_UART1_BAUD=115200 +CONFIG_UART1_BITS=8 +CONFIG_UART1_PARITY=0 +CONFIG_UART1_2STOP=0 +# CONFIG_UART1_IFLOWCONTROL is not set +# CONFIG_UART1_OFLOWCONTROL is not set + +# +# UART2 Configuration +# +CONFIG_UART2_RXBUFSIZE=256 +CONFIG_UART2_TXBUFSIZE=256 +CONFIG_UART2_BAUD=115200 +CONFIG_UART2_BITS=8 +CONFIG_UART2_PARITY=0 +CONFIG_UART2_2STOP=0 +# CONFIG_UART2_IFLOWCONTROL is not set +# CONFIG_UART2_OFLOWCONTROL is not set + +# +# UART3 Configuration +# +CONFIG_UART3_RXBUFSIZE=256 +CONFIG_UART3_TXBUFSIZE=256 +CONFIG_UART3_BAUD=115200 +CONFIG_UART3_BITS=8 +CONFIG_UART3_PARITY=0 +CONFIG_UART3_2STOP=0 +# CONFIG_UART3_IFLOWCONTROL is not set +# CONFIG_UART3_OFLOWCONTROL is not set + +# +# UART4 Configuration +# +CONFIG_UART4_RXBUFSIZE=256 +CONFIG_UART4_TXBUFSIZE=256 +CONFIG_UART4_BAUD=115200 +CONFIG_UART4_BITS=8 +CONFIG_UART4_PARITY=0 +CONFIG_UART4_2STOP=0 +# CONFIG_UART4_IFLOWCONTROL is not set +# CONFIG_UART4_OFLOWCONTROL is not set +# CONFIG_SENSOR is not set +# CONFIG_USBDEV is not set +# CONFIG_FOTA_DRIVER is not set + +# +# System Logging +# +# CONFIG_RAMLOG is not set +# CONFIG_SYSLOG_CONSOLE is not set + +# +# T-trace +# +# CONFIG_TTRACE is not set + +# +# Wireless Device Options +# +CONFIG_DRIVERS_WIRELESS=y +CONFIG_SCSC_WLAN=y +# CONFIG_SLSI_RX_PERFORMANCE_TEST is not set +CONFIG_SCSC_TX_FLOW_CONTROL=y +CONFIG_SCSC_ENABLE_PORT_CONTROL=y +# CONFIG_SCSC_WLAN_STA_ONLY is not set +# CONFIG_SCSC_WLAN_BLOCK_IPV6 is not set +# CONFIG_SCSC_WLAN_UDP_FLOWCONTROL is not set +# CONFIG_SCSC_WLAN_AUTO_RECOVERY is not set +CONFIG_SCSC_WLAN_POWER_SAVE=y +CONFIG_SCSC_WLAN_MAX_INTERFACES=1 +CONFIG_SCSC_CORE=y +CONFIG_SCSC_PLATFORM=y +# CONFIG_SCSC_WLANLITE is not set +# CONFIG_SCSC_DISABLE_WLAN_RESET is not set + +# +# Networking Support +# +CONFIG_ARCH_HAVE_NET=y +# CONFIG_ARCH_HAVE_PHY is not set +CONFIG_NET=y +CONFIG_NET_LWIP=y + +# +# LwIP options +# +CONFIG_NET_IPv4=y +CONFIG_NET_IP_DEFAULT_TTL=255 +# CONFIG_NET_IP_FORWARD is not set +CONFIG_NET_IP_OPTIONS_ALLOWED=y +CONFIG_NET_IP_FRAG=y +CONFIG_NET_IP_REASSEMBLY=y +CONFIG_NET_IPV4_REASS_MAX_PBUFS=20 +CONFIG_NET_IPV4_REASS_MAXAGE=5 +CONFIG_NET_IPv6=y +CONFIG_NET_IPv6_NUM_ADDRESSES=3 +# CONFIG_NET_IPv6_FORWARD is not set +# CONFIG_NET_IPv6_FRAG is not set +CONFIG_NET_IPv6_REASS=y +CONFIG_NET_IPV6_REASS_MAXAGE=60 +CONFIG_NET_IPv6_SEND_ROUTER_SOLICIT=y +CONFIG_NET_IPv6_AUTOCONFIG=y +CONFIG_NET_IPv6_DUP_DETECT_ATTEMPTS=1 +# CONFIG_NET_IPv6_PMTU_FOR_MULTICAST is not set + +# +# Socket support +# +CONFIG_NET_SOCKET=y +CONFIG_NSOCKET_DESCRIPTORS=20 +CONFIG_NET_TCP_KEEPALIVE=y +CONFIG_NET_RAW=y +# CONFIG_NET_SOCKET_OPTION_BROADCAST is not set +# CONFIG_NET_RANDOMIZE_INITIAL_LOCAL_PORTS is not set +# CONFIG_NET_SO_SNDTIMEO is not set +CONFIG_NET_SO_RCVTIMEO=y +# CONFIG_NET_SO_RCVBUF is not set +CONFIG_NET_SO_REUSE=y +# CONFIG_NET_SO_REUSE_RXTOALL is not set +CONFIG_NET_ARP=y +CONFIG_NET_ARP_TABLESIZE=10 +CONFIG_NET_ARP_QUEUEING=y +CONFIG_NET_ETHARP_TRUST_IP_MAC=y +CONFIG_NET_ETH_PAD_SIZE=0 +# CONFIG_NET_ARP_STATIC_ENTRIES is not set +CONFIG_NET_IPv6_ND=y +CONFIG_NET_IPv6_ND_QUEUEING=y +CONFIG_NET_IPv6_ND_QUEUE=20 +CONFIG_NET_IPv6_ND_NUM_NEIGHBORS=10 +CONFIG_NET_IPv6_ND_NUM_DESTINATIONS=10 +CONFIG_NET_IPv6_ND_NUM_PREFIXES=5 +CONFIG_NET_IPv6_ND_NUM_ROUTERS=3 +CONFIG_NET_IPv6_ND_MAX_MULTICAST_SOLICIT=3 +CONFIG_NET_IPv6_ND_MAX_UNICAST_SOLICIT=3 +CONFIG_NET_IPv6_ND_MAX_SOLICIT_INTERVAL=4000 +CONFIG_NET_IPv6_ND_REACHABLE_TIME=30000 +CONFIG_NET_IPv6_ND_RETRANS_TIMER=1000 +CONFIG_NET_IPv6_ND_DELAY_FIRST_PROBE_TIME=5000 +CONFIG_NET_IPv6_ND_ALLOW_RA_UPDATES=y +CONFIG_NET_IPv6_ND_TCP_REACHABILITY_HINTS=y +CONFIG_NET_IPv6_ND_RDNSS_MAX_DNS_SERVERS=0 +CONFIG_NET_UDP=y +# CONFIG_NET_NETBUF_RECVINFO is not set +CONFIG_NET_UDP_TTL=255 +# CONFIG_NET_UDPLITE is not set +CONFIG_NET_TCP=y +CONFIG_NET_TCP_TTL=255 +CONFIG_NET_TCP_WND=58400 +CONFIG_NET_TCP_MAXRTX=12 +CONFIG_NET_TCP_SYNMAXRTX=6 +CONFIG_NET_TCP_QUEUE_OOSEQ=y +CONFIG_NET_TCP_MSS=1460 +CONFIG_NET_TCP_CALCULATE_EFF_SEND_MSS=y +CONFIG_NET_TCP_SND_BUF=29200 +CONFIG_NET_TCP_SND_QUEUELEN=80 +# CONFIG_NET_TCP_LISTEN_BACKLOG is not set +CONFIG_NET_TCP_OVERSIZE=536 +# CONFIG_NET_TCP_TIMESTAMPS is not set +CONFIG_NET_TCP_WND_UPDATE_THRESHOLD=536 +CONFIG_NET_ICMP=y +CONFIG_NET_ICMP_TTL=255 +# CONFIG_NET_BROADCAST_PING is not set +# CONFIG_NET_MULTICAST_PING4 is not set +CONFIG_NET_IPv6_ICMP=y +CONFIG_NET_IPv6_ICMP_DATASIZE=8 +CONFIG_NET_IPv6_ICMP_HL=255 +# CONFIG_NET_MULTICAST_PING6 is not set +CONFIG_NET_LWIP_IGMP=y +CONFIG_NET_LWIP_MEMP_NUM_IGMP_GROUP=8 +CONFIG_NET_IPv6_MLD=y +CONFIG_NET_IPv6_MLD_GROUP=4 +# CONFIG_NET_IPv6_DHCP is not set + +# +# LWIP Mailbox Configurations +# +CONFIG_NET_TCPIP_MBOX_SIZE=64 +CONFIG_NET_DEFAULT_ACCEPTMBOX_SIZE=64 +CONFIG_NET_DEFAULT_RAW_RECVMBOX_SIZE=64 +CONFIG_NET_DEFAULT_TCP_RECVMBOX_SIZE=54 +CONFIG_NET_DEFAULT_UDP_RECVMBOX_SIZE=64 + +# +# Memory Configurations +# +CONFIG_NET_MEM_ALIGNMENT=4 +# CONFIG_NET_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT is not set +# CONFIG_NET_MEM_LIBC_MALLOC is not set +CONFIG_NET_MEMP_MEM_MALLOC=y +# CONFIG_NET_MEM_USE_POOLS is not set +CONFIG_NET_MEM_SIZE=153600 + +# +# LWIP Task Configurations +# +# CONFIG_NET_TCPIP_CORE_LOCKING is not set +# CONFIG_NET_TCPIP_CORE_LOCKING_INPUT is not set +CONFIG_NET_TCPIP_THREAD_NAME="LWIP_TCP/IP" +CONFIG_NET_TCPIP_THREAD_PRIO=110 +CONFIG_NET_TCPIP_THREAD_STACKSIZE=4096 +CONFIG_NET_COMPAT_MUTEX=y +CONFIG_NET_SYS_LIGHTWEIGHT_PROT=y +CONFIG_NET_DEFAULT_THREAD_NAME="lwIP" +CONFIG_NET_DEFAULT_THREAD_PRIO=1 +CONFIG_NET_DEFAULT_THREAD_STACKSIZE=0 + +# +# Debug Options for Network +# +# CONFIG_NET_LWIP_ASSERT is not set +# CONFIG_NET_LWIP_ERROR is not set +# CONFIG_NET_LWIP_DEBUG is not set + +# +# Enable Statistics +# +CONFIG_NET_STATS=y +CONFIG_NET_STATS_DISPLAY=y +CONFIG_NET_LINK_STATS=y +CONFIG_NET_ETHARP_STATS=y +CONFIG_NET_IP_STATS=y +# CONFIG_NET_IPFRAG_STATS is not set +# CONFIG_NET_ICMP_STATS is not set +CONFIG_NET_UDP_STATS=y +CONFIG_NET_TCP_STATS=y +CONFIG_NET_MEM_STATS=y +CONFIG_NET_SYS_STATS=y +# CONFIG_NET_IPv6_STATS is not set +# CONFIG_NET_IPv6_ICMP_STATS is not set +# CONFIG_NET_IPv6_MLD_STATS is not set +# CONFIG_NET_IPv6_ND_STATS is not set +# CONFIG_NET_LWIP_VLAN is not set +CONFIG_NET_LWIP_LOOPBACK_INTERFACE=y +# CONFIG_NET_LWIP_SLIP_INTERFACE is not set +# CONFIG_NET_LWIP_PPP_SUPPORT is not set +# CONFIG_NET_LWIP_SNMP is not set + +# +# Interface Name +# +CONFIG_NET_ETH_IFNAME="en" +CONFIG_NET_LOOP_IFNAME="lo" +CONFIG_NET_STA_IFNAME="wl" +CONFIG_NET_SOFTAP_IFNAME="sa" +CONFIG_NET_LWIP_NETDB=y +CONFIG_NET_DNS_TABLE_SIZE=4 +CONFIG_NET_DNS_MAX_NAME_LENGTH=256 +CONFIG_NET_DNS_MAX_SERVERS=2 +# CONFIG_NET_DNS_DOES_NAME_CHECK is not set +CONFIG_NET_DNS_SECURE=0 +# CONFIG_NET_DNS_LOCAL_HOSTLIST is not set + +# +# Driver buffer configuration +# +CONFIG_NET_MULTIBUFFER=y +CONFIG_NET_ETH_MTU=590 +CONFIG_NET_GUARDSIZE=2 + +# +# Data link support +# +# CONFIG_NET_MULTILINK is not set +CONFIG_NET_ETHERNET=y + +# +# Network Device Operations +# +# CONFIG_NETDEV_PHY_IOCTL is not set + +# +# Protocols +# +CONFIG_NETUTILS_DHCPD=y +CONFIG_NETUTILS_DHCPD_IGNOREBROADCAST=y +CONFIG_NETUTILS_DHCPD_INTERFACE="wl1" +CONFIG_NETUTILS_DHCPD_LEASETIME=864000 +CONFIG_NETUTILS_DHCPD_MINLEASETIME=86400 +CONFIG_NETUTILS_DHCPD_MAXLEASETIME=2592000 +CONFIG_NETUTILS_DHCPD_MAXLEASES=6 +CONFIG_NETUTILS_DHCPD_STARTIP=0xc0a82f02 +CONFIG_NETUTILS_DHCPD_ROUTERIP=0xc0a82f01 +CONFIG_NETUTILS_DHCPD_NETMASK=0xffffff00 +CONFIG_NETUTILS_DHCPD_DNSIP=0x08080808 +CONFIG_NETUTILS_DHCPD_OFFERTIME=3600 +CONFIG_NETUTILS_DHCPD_DECLINETIME=3600 +# CONFIG_NETUTILS_XMLRPC is not set +# CONFIG_NETUTILS_NTPCLIENT is not set +# CONFIG_NETUTILS_WEBSERVER is not set +# CONFIG_NETUTILS_FTPC is not set +# CONFIG_NETUTILS_MDNS is not set +# CONFIG_NETUTILS_FTPD is not set +CONFIG_NETUTILS_DHCPC=y +# CONFIG_NETUTILS_WEBSOCKET is not set +# CONFIG_NETUTILS_LIBCOAP is not set +# CONFIG_NETUTILS_TFTPC is not set +# CONFIG_NETUTILS_TELNETD is not set +# CONFIG_NETUTILS_SMTP is not set +# CONFIG_NETUTILS_MQTT is not set +CONFIG_NET_SECURITY_TLS=y +CONFIG_TLS_MPI_MAX_SIZE=512 + +# +# Wireless +# +CONFIG_WIFI_MANAGER=y +CONFIG_SELECT_WPA_SUPPLICANT=y +# CONFIG_SELECT_PROPIETARY_SUPPLICANT is not set +# CONFIG_SELECT_NO_DRIVER is not set +CONFIG_SELECT_SCSC_WLAN=y +# CONFIG_SELECT_PROPIETARY_WLAN is not set +CONFIG_NETUTILS_WIFI=y +CONFIG_SLSI_WIFI_DEFAULT_WLAN_COUNTRY_CODE="00" +CONFIG_SLSI_WIFI_DEFAULT_WLAN_TX_POWER=30 +# CONFIG_SLSI_WIFI_FILESYSTEM_SUPPORT is not set + +# +# wpa_supplicant +# +CONFIG_WPA_SUPPLICANT=y +CONFIG_WPA_SUPPLICANT_PRIORITY=100 +CONFIG_WPA_SUPPLICANT_STACKSIZE=16384 +CONFIG_WPA_SUPPLICANT_ENTRYPOINT="wpa_supplicant_main" +CONFIG_CTRL_IFACE=y +CONFIG_CTRL_IFACE_FIFO=y +CONFIG_WPA_CTRL_FIFO_DEV_REQ="/dev/wpa_ctrl_req" +CONFIG_WPA_CTRL_FIFO_DEV_CFM="/dev/wpa_ctrl_cfm" +CONFIG_WPA_CTRL_FIFO_DEV_GLOBAL_REQ="/dev/wpa_ctrl_global_req" +CONFIG_WPA_CTRL_FIFO_DEV_GLOBAL_CFM="/dev/wpa_ctrl_global_cfm" +CONFIG_WPA_MONITOR_FIFO_DEV="/dev/wpa_monitor" +CONFIG_WPA_CTRL_FIFO_MK_MODE=666 +CONFIG_ELOOP_POLL=y +# CONFIG_WPA_SUPPLICANT_CMD is not set +CONFIG_DRIVER_T20=y +# CONFIG_ENABLE_EAP_FOR_SUPPLICANT is not set +CONFIG_WIFIMGR_SOFTAP_IFNAME="wl1" +CONFIG_WIFIMGR_STA_IFNAME="wl1" +# CONFIG_WIFIMGR_DISABLE_AUTO_GET_IP is not set +# CONFIG_DISABLE_EXTERNAL_AUTOCONNECT is not set + +# +# Network utilities +# +CONFIG_NETUTILS_NETLIB=y +CONFIG_NET_NETMON=y + +# +# Audio Support +# +# CONFIG_AUDIO is not set + +# +# Media Support +# + +# +# File Systems +# +# CONFIG_DISABLE_MOUNTPOINT is not set +# CONFIG_DISABLE_PSEUDOFS_OPERATIONS is not set +CONFIG_FS_READABLE=y +CONFIG_FS_WRITABLE=y +# CONFIG_FS_AIO is not set +# CONFIG_FS_NAMED_SEMAPHORES is not set +CONFIG_FS_MQUEUE_MPATH="/var/mqueue" +CONFIG_FS_SMARTFS=y + +# +# SMARTFS options +# +CONFIG_SMARTFS_ERASEDSTATE=0xff +CONFIG_SMARTFS_MAXNAMLEN=32 +# CONFIG_SMARTFS_MULTI_ROOT_DIRS is not set +CONFIG_SMARTFS_ALIGNED_ACCESS=y +# CONFIG_SMARTFS_BAD_SECTOR is not set +# CONFIG_SMARTFS_DYNAMIC_HEADER is not set +# CONFIG_SMARTFS_JOURNALING is not set +# CONFIG_SMARTFS_SECTOR_RECOVERY is not set +CONFIG_FS_PROCFS=y +# CONFIG_FS_AUTOMOUNT_PROCFS is not set + +# +# Exclude individual procfs entries +# +# CONFIG_FS_PROCFS_EXCLUDE_PROCESS is not set +# CONFIG_FS_PROCFS_EXCLUDE_UPTIME is not set +# CONFIG_FS_PROCFS_EXCLUDE_VERSION is not set +# CONFIG_FS_PROCFS_EXCLUDE_MTD is not set +# CONFIG_FS_PROCFS_EXCLUDE_PARTITIONS is not set +# CONFIG_FS_PROCFS_EXCLUDE_SMARTFS is not set +# CONFIG_FS_PROCFS_EXCLUDE_POWER is not set +CONFIG_FS_ROMFS=y +# CONFIG_FS_TMPFS is not set + +# +# Block Driver Configurations +# +CONFIG_RAMDISK=y + +# +# MTD Configuration +# +CONFIG_MTD=y +CONFIG_MTD_PARTITION=y +CONFIG_MTD_PARTITION_NAMES=y +CONFIG_MTD_PROGMEM=y +CONFIG_MTD_FTL=y + +# +# MTD_FTL Configurations +# +CONFIG_MTD_CONFIG=y + +# +# MTD Configurations +# +# CONFIG_MTD_CONFIG_RAM_CONSOLIDATE is not set +CONFIG_MTD_CONFIG_ERASEDVALUE=0xff +# CONFIG_MTD_BYTE_WRITE is not set + +# +# MTD Device Drivers +# +# CONFIG_MTD_M25P is not set +# CONFIG_RAMMTD is not set +CONFIG_MTD_SMART=y + +# +# SMART Device options +# +CONFIG_MTD_SMART_SECTOR_SIZE=512 +# CONFIG_MTD_SMART_WEAR_LEVEL is not set +# CONFIG_MTD_SMART_ENABLE_CRC is not set +# CONFIG_MTD_SMART_SECTOR_ERASE_DEBUG is not set +# CONFIG_MTD_SMART_ALLOC_DEBUG is not set +# CONFIG_MTD_W25 is not set + +# +# System Logging +# +# CONFIG_SYSLOG is not set +# CONFIG_SYSLOG_TIMESTAMP is not set + +# +# Database +# +# CONFIG_ARASTORAGE is not set + +# +# Memory Management +# +# CONFIG_REALLOC_DISABLE_NEIGHBOR_EXTENSION is not set +# CONFIG_MM_SMALL is not set +CONFIG_MM_REGIONS=1 +# CONFIG_GRAN is not set + +# +# Power Management +# +CONFIG_PM=y +# CONFIG_DEBUG_PM is not set +# CONFIG_PM_TEST is not set +CONFIG_PM_DEVNAME_LEN=32 +# CONFIG_PM_METRICS is not set +CONFIG_PM_SLICEMS=100 +CONFIG_PM_NDOMAINS=1 +CONFIG_PM_MEMORY=2 +CONFIG_PM_COEFN=1 +CONFIG_PM_COEF1=1 +CONFIG_PM_COEF2=1 +CONFIG_PM_COEF3=1 +CONFIG_PM_COEF4=1 +CONFIG_PM_COEF5=1 +CONFIG_PM_IDLEENTER_THRESH=1 +CONFIG_PM_IDLEEXIT_THRESH=2 +CONFIG_PM_IDLEENTER_COUNT=30 +CONFIG_PM_STANDBYENTER_THRESH=1 +CONFIG_PM_STANDBYEXIT_THRESH=2 +CONFIG_PM_STANDBYENTER_COUNT=50 +CONFIG_PM_SLEEPENTER_THRESH=1 +CONFIG_PM_SLEEPEXIT_THRESH=2 +CONFIG_PM_SLEEPENTER_COUNT=70 + +# +# Debug Options +# +# CONFIG_DEBUG is not set +# CONFIG_DEBUG_ERROR is not set +# CONFIG_DEBUG_WARN is not set +# CONFIG_DEBUG_VERBOSE is not set + +# +# Subsystem Debug Options +# +# CONFIG_DEBUG_LIB is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_DEBUG_IOTBUS is not set +# CONFIG_DEBUG_MM is not set +# CONFIG_DEBUG_NET is not set +# CONFIG_DEBUG_NET_ERROR is not set +# CONFIG_DEBUG_NET_INFO is not set +# CONFIG_DEBUG_SCHED is not set +# CONFIG_DEBUG_TASH is not set +# CONFIG_DEBUG_WLAN is not set + +# +# SLSI WLAN FW Debug Options +# +# CONFIG_SCSC_ENABLE_FWFAULT_LOG is not set + +# +# SLSI WLAN Driver Debug Options +# +# CONFIG_DEBUG_WLAN_DRIVER_ERROR is not set +# CONFIG_DEBUG_WLAN_DRIVER_DEBUG is not set +# CONFIG_DEBUG_WLAN_DRIVER_MORE is not set +# CONFIG_DEBUG_WLAN_DRIVER_INFO is not set + +# +# SLSI WPA Supplicant Debug Options +# +# CONFIG_DEBUG_WLAN_SUPPLICANT_ERROR is not set +# CONFIG_DEBUG_WLAN_SUPPLICANT_DEBUG is not set +# CONFIG_DEBUG_WLAN_SUPPLICANT_MORE is not set +# CONFIG_DEBUG_WLAN_SUPPLICANT_INFO is not set + +# +# SLSI Wi-Fi API Debug Options +# +# CONFIG_DEBUG_WLAN_API_ERROR is not set +# CONFIG_DEBUG_WLAN_API_DEBUG is not set +# CONFIG_DEBUG_WLAN_API_INFO is not set + +# +# OS Function Debug Options +# +# CONFIG_ARCH_HAVE_HEAPCHECK is not set +# CONFIG_DEBUG_MM_HEAPINFO is not set +# CONFIG_DEBUG_IRQ is not set + +# +# Driver Debug Options +# +# CONFIG_DEBUG_I2S is not set +# CONFIG_DEBUG_PWM is not set +# CONFIG_DEBUG_RTC is not set +# CONFIG_DEBUG_SPI is not set +# CONFIG_DEBUG_WATCHDOG is not set + +# +# System Debug Options +# +# CONFIG_DEBUG_SYSTEM is not set + +# +# Stack Debug Options +# +CONFIG_ARCH_HAVE_STACKCHECK=y +CONFIG_STACK_COLORATION=y + +# +# Build Debug Options +# +# CONFIG_DEBUG_SYMBOLS is not set +# CONFIG_FRAME_POINTER is not set + +# +# Logger Module +# +CONFIG_LOGM=y +# CONFIG_PRINTF2LOGM is not set +CONFIG_SYSLOG2LOGM=y +# CONFIG_LOGM_TIMESTAMP is not set +CONFIG_LOGM_BUFFER_SIZE=10240 +CONFIG_LOGM_PRINT_INTERVAL=1000 +CONFIG_LOGM_TASK_PRIORITY=110 +CONFIG_LOGM_TASK_STACKSIZE=2048 +# CONFIG_LOGM_TEST is not set + +# +# Built-in Libraries +# + +# +# Standard C Library Options +# +CONFIG_STDIO_BUFFER_SIZE=64 +CONFIG_STDIO_LINEBUFFER=y +CONFIG_NUNGET_CHARS=2 +CONFIG_LIB_HOMEDIR="/" +CONFIG_LIBM=y +# CONFIG_NOPRINTF_FIELDWIDTH is not set +CONFIG_LIBC_FLOATINGPOINT=y +CONFIG_LIBC_FLOATPRECISION=6 +CONFIG_LIBC_SCANSET=y +# CONFIG_NOPRINTF_LONGLONG_TO_ASCII is not set +CONFIG_LIBC_IOCTL_VARIADIC=y +# CONFIG_LIBC_WCHAR is not set +# CONFIG_LIBC_LOCALE is not set +CONFIG_LIB_RAND_ORDER=1 +# CONFIG_EOL_IS_CR is not set +# CONFIG_EOL_IS_LF is not set +# CONFIG_EOL_IS_BOTH_CRLF is not set +CONFIG_EOL_IS_EITHER_CRLF=y +CONFIG_LIBC_STRERROR=y +# CONFIG_LIBC_STRERROR_SHORT is not set +# CONFIG_LIBC_PERROR_STDOUT is not set +CONFIG_LIBC_TMPDIR="/tmp" +CONFIG_LIBC_MAX_TMPFILE=32 +CONFIG_ARCH_LOWPUTC=y +# CONFIG_LIBC_LOCALTIME is not set +# CONFIG_TIME_EXTENDED is not set +CONFIG_LIB_SENDFILE_BUFSIZE=512 +CONFIG_ARCH_OPTIMIZED_FUNCTIONS=y +# CONFIG_ARCH_MEMCPY is not set +CONFIG_MEMCPY_VIK=y +# CONFIG_MEMCPY_PRE_INC_PTRS is not set +CONFIG_MEMCPY_INDEXED_COPY=y +# CONFIG_MEMCPY_64BIT is not set +# CONFIG_ARCH_MEMCMP is not set +# CONFIG_ARCH_MEMMOVE is not set +# CONFIG_ARCH_MEMSET is not set +# CONFIG_MEMSET_OPTSPEED is not set +# CONFIG_ARCH_STRCHR is not set +# CONFIG_ARCH_STRCMP is not set +# CONFIG_ARCH_STRCPY is not set +# CONFIG_ARCH_STRNCPY is not set +# CONFIG_ARCH_STRLEN is not set +# CONFIG_ARCH_STRNLEN is not set +# CONFIG_ARCH_BZERO is not set + +# +# Non-standard Library Support +# + +# +# Basic CXX Support +# +# CONFIG_C99_BOOL8 is not set +# CONFIG_HAVE_CXX is not set + +# +# External Libraries +# +# CONFIG_AVS_DEVICE_SDK is not set +# CONFIG_AWS_SDK is not set +# CONFIG_NETUTILS_CODECS is not set + +# +# CURL Options +# +# CONFIG_ENABLE_CURL is not set +# CONFIG_ERROR_REPORT is not set +# CONFIG_ENABLE_IOTIVITY is not set +CONFIG_NETUTILS_JSON=y +# CONFIG_LIBTUV is not set +# CONFIG_LWM2M_WAKAAMA is not set +# CONFIG_STRESS_TOOL is not set +# CONFIG_VOICE_SOFTWARE_EPD is not set + +# +# Application Configuration +# + +# +# Application entry point list +# +# CONFIG_ENTRY_MANUAL is not set +# CONFIG_ENTRY_HELLO is not set +CONFIG_ENTRY_IOTJS_STARTUP=y +CONFIG_USER_ENTRYPOINT="iotjs_startup_main" +CONFIG_BUILTIN_APPS=y + +# +# Examples +# +# CONFIG_EXAMPLES_AVS_TEST is not set +# CONFIG_EXAMPLES_AWS is not set +# CONFIG_EXAMPLES_CURLTEST is not set +# CONFIG_EXAMPLES_DNSCLIENT_TEST is not set +# CONFIG_EXAMPLES_DTLS_CLIENT is not set +# CONFIG_EXAMPLES_DTLS_SERVER is not set +# CONFIG_EXAMPLES_EEPROM_TEST is not set +# CONFIG_EXAMPLES_EVENTLOOP is not set +# CONFIG_EXAMPLES_FOTA_SAMPLE is not set +# CONFIG_FILESYSTEM_HELPER_ENABLE is not set +CONFIG_EXAMPLES_HELLO=y +# CONFIG_EXAMPLES_HELLOXX is not set +# CONFIG_EXAMPLES_IOTBUS_TEST is not set +CONFIG_EXAMPLES_IOTJS_STARTUP=y +CONFIG_EXAMPLES_IOTJS_STARTUP_JS_FILE="/rom/example/index.js" +# CONFIG_EXAMPLES_IOTJS_STARTUP_WIFI is not set +# CONFIG_EXAMPLES_KERNEL_SAMPLE is not set +# CONFIG_EXAMPLES_LIBTUV is not set +# CONFIG_EXAMPLES_NETTEST is not set +# CONFIG_EXAMPLES_PROC_TEST is not set +# CONFIG_EXAMPLES_SELECT_TEST is not set +# CONFIG_EXAMPLES_SENSORBOARD is not set +# CONFIG_EXAMPLES_SETJMP_TEST is not set +CONFIG_EXAMPLES_SLSIWIFI=y +CONFIG_EXAMPLES_SLSIWIFI_PRIORITY=50 +CONFIG_EXAMPLES_SLSIWIFI_STACKSIZE=2048 +# CONFIG_EXAMPLES_SMART is not set +# CONFIG_EXAMPLES_SMART_TEST is not set +# CONFIG_EXAMPLES_SPEECH_DETECTOR_TEST is not set +# CONFIG_EXAMPLES_ST_THINGS is not set +# CONFIG_EXAMPLES_TESTCASE is not set +# CONFIG_EXAMPLES_TLS_BENCHMARK is not set +# CONFIG_EXAMPLES_TLS_CLIENT is not set +# CONFIG_EXAMPLES_TLS_SELFTEST is not set +# CONFIG_EXAMPLES_TLS_SERVER is not set +# CONFIG_EXAMPLES_WIFIMANAGER_TEST is not set + +# +# Platform-specific Support +# +# CONFIG_PLATFORM_CONFIGDATA is not set + +# +# Shell +# +CONFIG_TASH=y +CONFIG_TASH_MAX_COMMANDS=132 +# CONFIG_TASH_USLEEP is not set +CONFIG_TASH_COMMAND_INTERFACE=y +CONFIG_TASH_CMDTASK_STACKSIZE=4096 +CONFIG_TASH_CMDTASK_PRIORITY=100 +# CONFIG_TASH_SCRIPT is not set + +# +# System Libraries and Add-Ons +# +# CONFIG_SYSTEM_CLE is not set +# CONFIG_SYSTEM_CUTERM is not set +# CONFIG_SYSTEM_FLASH_ERASEALL is not set +# CONFIG_SYSTEM_FOTA_HAL is not set +# CONFIG_SYSTEM_I2CTOOL is not set +# CONFIG_SYSTEM_INIFILE is not set +CONFIG_SYSTEM_PREAPP_INIT=y +CONFIG_SYSTEM_PREAPP_STACKSIZE=2048 +# CONFIG_SYSTEM_INSTALL is not set +CONFIG_SYSTEM_IPERF=y +# CONFIG_SYSTEM_NETDB is not set +CONFIG_SYSTEM_RAMTEST=y +CONFIG_SYSTEM_RAMTEST_PRIORITY=100 +CONFIG_SYSTEM_RAMTEST_STACKSIZE=1024 +CONFIG_SYSTEM_READLINE=y +CONFIG_READLINE_ECHO=y +CONFIG_SYSTEM_INFORMATION=y +CONFIG_KERNEL_CMDS=y +CONFIG_FS_CMDS=y +CONFIG_FSCMD_BUFFER_LEN=64 +CONFIG_NET_CMDS=y +CONFIG_NET_PING_CMD=y +CONFIG_NET_PING_CMD_ICOUNT=5 +CONFIG_ENABLE_DATE_CMD=y +CONFIG_ENABLE_ENV_GET_CMD=y +CONFIG_ENABLE_ENV_SET_CMD=y +CONFIG_ENABLE_ENV_UNSET_CMD=y +CONFIG_ENABLE_FREE_CMD=y +CONFIG_ENABLE_HEAPINFO_CMD=y +# CONFIG_HEAPINFO_USER_GROUP is not set +# CONFIG_ENABLE_IRQINFO_CMD is not set +CONFIG_ENABLE_KILL_CMD=y +CONFIG_ENABLE_KILLALL_CMD=y +CONFIG_ENABLE_PS_CMD=y +CONFIG_ENABLE_STACKMONITOR_CMD=y +CONFIG_STACKMONITOR_PRIORITY=100 +CONFIG_STACKMONITOR_INTERVAL=5 +CONFIG_ENABLE_UPTIME_CMD=y +# CONFIG_SYSTEM_VI is not set + +# +# Runtime Environment +# +CONFIG_ENABLE_IOTJS=y +CONFIG_IOTJS_PRIORITY=100 +CONFIG_IOTJS_STACKSIZE=32768 +CONFIG_IOTJS_JERRY_HEAP=128 + +# +# Device Management +# +# CONFIG_DM is not set + +# +# Task manager +# +# CONFIG_TASK_MANAGER is not set + +# +# Event Loop Framework +# +# CONFIG_EVENTLOOP is not set + +# +# Things Management +# +# CONFIG_ST_THINGS is not set + +# +# IoTBus Framework +# +CONFIG_IOTBUS=y +CONFIG_IOTBUS_GPIO=y +CONFIG_IOTBUS_I2C=y +CONFIG_IOTBUS_PWM=y +CONFIG_IOTBUS_SPI=y +CONFIG_IOTBUS_UART=y diff --git a/deps/http-parser b/deps/http-parser index d6a49efe3f..f8f84b34db 160000 --- a/deps/http-parser +++ b/deps/http-parser @@ -1 +1 @@ -Subproject commit d6a49efe3ff667a35145119b504f1f583d56ea57 +Subproject commit f8f84b34db144ce54682333b360cbca3259b9536 diff --git a/deps/jerry b/deps/jerry index 7cc9d65c09..8ba0d1b6ee 160000 --- a/deps/jerry +++ b/deps/jerry @@ -1 +1 @@ -Subproject commit 7cc9d65c095c6631bb547d863dfeadc470d8dfc6 +Subproject commit 8ba0d1b6ee5a065a42f3b306771ad8e3c0d819bc diff --git a/deps/libtuv b/deps/libtuv index b7fa7888ef..8b169052d6 160000 --- a/deps/libtuv +++ b/deps/libtuv @@ -1 +1 @@ -Subproject commit b7fa7888effb9d3f0ad91091aa2e5d687295718c +Subproject commit 8b169052d6e658c6e8701d385b456cc6c7de876c diff --git a/deps/mbedtls b/deps/mbedtls new file mode 160000 index 0000000000..8be0e6db41 --- /dev/null +++ b/deps/mbedtls @@ -0,0 +1 @@ +Subproject commit 8be0e6db41b4a085e90cb03983f99d3a5158d450 diff --git a/docs/Developer's-Guide.md b/docs/Developer's-Guide.md new file mode 100644 index 0000000000..dd75215ba7 --- /dev/null +++ b/docs/Developer's-Guide.md @@ -0,0 +1,4 @@ +To contribute to the IoT.js Project (such as reporting bugs and submitting patches): +* Follow the [Development Process](devs/Development-Process.md) and [GitHub contributor guidelines](https://guides.github.com/activities/contributing-to-open-source/). +* Add the [IoT.js DCO](devs/IoT.js-Developer's-Certificate-of-Origin-1.0.md) signoff to each commit message during development. +* Add the [License](License.md) if you introduce any new source code or script files diff --git a/docs/Getting-Started.md b/docs/Getting-Started.md new file mode 100644 index 0000000000..c6c12e18c6 --- /dev/null +++ b/docs/Getting-Started.md @@ -0,0 +1,51 @@ +### Supported platforms +Current supported platforms are **Linux, [NuttX][nuttx-site], [Tizen][tizen-site] and [TizenRT][tizenrt-site]** + +OSX 10.10 as development host + +* [Build for x86 / Linux](build/Build-for-x86-Linux.md): Ubuntu 14.04 is used as a base platform. +* [Build for Raspberry Pi 2 / Linux](build/Build-for-RPi2-Linux.md) +* [Build for Raspberry Pi 3 / Tizen](build/Build-for-RPi3-Tizen.md) +* [Build for Stm32f4 / NuttX](build/Build-for-STM32F4-NuttX.md) +* [Build for ARTIK053 / TizenRT](build/Build-for-ARTIK053-TizenRT.md) +* [Build for ARTIK530 / Tizen](build/Build-for-RPi3-Tizen.md) +* [Build for OpenWrt (non-tested)](build/Build-for-OpenWrt.md) +* [Build for Windows (experimental)](build/Build-for-Windows.md) + +#### H/W boards +* Current supporting + * STM32F4-Discovery + BB + * Raspberry Pi 2 + * Raspberry Pi 3 + * Samsung ARTIK 053 + * Samsung ARTIK 530 + +We will support the correct behavior of APIs for above environments. However, since IoT.js is targeting various kind IoT devices and platforms, single implementation cannot be the best practice for every environments. Therefore embedders should be in charge of optimization for their own environments. For more details on optimization, see the [Optimization Tips](devs/Optimization-Tips.md) page. + + +### Build script +There is a [script](build/Build-Script.md) to help you build IoT.js called "[build.py](https://github.com/jerryscript-project/iotjs/blob/master/tools/build.py)" in source repository. Run `tools/build.py --help` command to check all of the build options. + +#### How to Build + +```bash + tools/build.py --clean +``` + +#### Frequently used build options + +`--clean` Clean build directory before build (default: False). + +`--no-snapshot` Disable snapshot generation for IoT.js. It is useful for debugging sessions. + +`--profile PROFILE` Specify the module profile file for IoT.js. It is used for enable and disable modules. See also ["How to write a new module"](devs/Writing-New-Module.md#profile) + +`--run-test [{full,quiet}]` Execute tests after build, optional argument specifies the level of output for the test runner. + +`--jerry-debugger` Enable JerryScript debugger, so JavaScript could can be investigated with an available debugger client (eg.: [Python Debugger Console](https://github.com/jerryscript-project/jerryscript/blob/master/jerry-debugger/jerry_client.py) or [IoT.js Code](https://github.com/jerryscript-project/iotjscode/)). See also ["Use JerryScript Debugger"](devs/Use-JerryScript-Debugger.md). + +`--js-backtrace {ON,OFF}` Enable/disable backtrace information of JavaScript code (default: ON in debug and OFF in release build). + +[nuttx-site]: http://nuttx.org/ +[tizen-site]: https://www.tizen.org/ +[tizenrt-site]: https://wiki.tizen.org/Tizen_RT diff --git a/docs/README.md b/docs/README.md index c131ac090c..a881a00d39 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,18 +1,33 @@ Welcome to the IoT.js! -* If you would like to try IoT.js, please check [Getting Started](help/Getting-Started.md). -* If you would like to jump into IoT.js, please follow [Development Process](help/Development-Process.md) of IoT.js. - -### IoT.js -- Project Overview > IoT.js is a framework for "Internet of Things" built on > lightweight JavaScript interpreter ['JerryScript'](https://github.com/jerryscript-project/jerryscript) > and libtuv for event driven(non-blocking I/O model) similar to node.js. +### IoT.js Wiki + +**About** - [License](License.md) -
+- [Governance](contributing/Governance.md) + +**[Getting Started](Getting-Started.md)** +- [x86 / Linux](build/Build-for-x86-Linux.md) +- [Raspberry Pi 2 / Linux](build/Build-for-RPi2-Linux.md) +- [Raspberry Pi 3 / Tizen](build/Build-for-RPi3-Tizen.md) +- [Stm32f4 / NuttX](build/Build-for-STM32F4-NuttX.md) +- [ARTIK053 / TizenRT](build/Build-for-ARTIK053-TizenRT.md) +**[Developer Guide](Developer's-Guide.md)** +- [Development Process](devs/Development-Process.md) +- [Certificate of Origin](devs/IoT.js-Developer's-Certificate-of-Origin-1.0.md) +- [Test Guidelines](devs/Test-Guidelines.md) +- [Coding Style Guidelines](devs/Coding-Style-Guidelines.md) +- [API Document Guidelines](devs/API-Document-Guidelines.md) +- [Developer Tutorial](devs/Developer-Tutorial.md) +- [Advanced Development](devs/Advanced-Development.md) +- [IoT.js API Reference](api/IoT.js-API-reference.md) -### [Getting Started](help/Getting-Started.md) - Developer guide -### [Getting Involved](help/Getting-involved.md) -### Roadmap(TBD) +**Contributing** +- [Patch Submission Process](contributing/Patch-Submission-Process.md) +- [Community Guideline](contributing/Community-Guidelines.md) +- [Assigned People](contributing/Assigned-People.md) diff --git a/docs/api/IoT.js-API-ADC.md b/docs/api/IoT.js-API-ADC.md index 7635269e40..6945c8331b 100644 --- a/docs/api/IoT.js-API-ADC.md +++ b/docs/api/IoT.js-API-ADC.md @@ -2,18 +2,19 @@ The following table shows ADC module APIs available for each platform. -| | Linux
(Ubuntu) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | -| :---: | :---: | :---: | :---: | -| adc.open | O | X | O | -| adcpin.read | O | X | O | -| adcpin.readSync | O | X | O | -| adcpin.close | O | X | O | -| adcpin.closeSync | O | X | O | +| | Linux
(Ubuntu) | Tizen
(Raspberry Pi) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | TizenRT
(Artik053) | +| :---: | :---: | :---: | :---: | :---: | :---: | +| adc.open | X | X | X | O | O | +| adc.openSync | X | X | X | O | O | +| adcpin.read | X | X | X | O | O | +| adcpin.readSync | X | X | X | O | O | +| adcpin.close | X | X | X | O | O | +| adcpin.closeSync | X | X | X | O | O | -## Class: ADC +# ADC -This class allows reading analogue data from hardware pins. +This module allows reading analogue data from hardware pins. The hardware pins can be read from or written to, therefore they are called bidirectional IO pins. This module provides the reading part. @@ -21,25 +22,20 @@ On NuttX, you have to know the number of pins that is defined on the target boar * [STM32F4-discovery](../targets/nuttx/stm32f4dis/IoT.js-API-Stm32f4dis.md#adc-pin) -### new ADC() - -Returns a new ADC object which can open an ADC pin. - - -### adc.open(configuration[, callback]) +### adc.open(configuration, callback) * `configuration` {Object} * `device` {string} Mandatory configuration on Linux. - * `pin` {int} Mandatory configuration on NuttX. + * `pin` {number} Mandatory configuration on NuttX and TizenRT. * `callback` {Function} * `err`: {Error|null} -* Returns: `AdcPin` {adc.AdcPin} + * `adcpin` {Object} An instance of AdcPin. +* Returns: {Object} An instance of AdcPin. -Opens an ADC pin with the specified configuration. +Opens an ADC pin with the specified configuration asynchronously. **Example** ```js -var Adc = require('adc'); -var adc = new Adc(); +var adc = require('adc'); var adc0 = adc.open({ device: '/sys/devices/12d10000.adc/iio:device0/in_voltage0_raw' }, function(err) { @@ -49,13 +45,31 @@ var adc0 = adc.open({ }); ``` +### adc.openSync(configuration) +* `configuration` {Object} + * `device` {string} Mandatory configuration on Linux. + * `pin` {number} Mandatory configuration on NuttX and TizenRT. +* `callback` {Function} + * `err`: {Error|null} +* Returns: {Object} An instance of AdcPin. + +Opens an ADC pin with the specified configuration synchronously. + +**Example** +```js +var adc = require('adc'); +var adc0 = adc.openSync({ + device: '/sys/devices/12d10000.adc/iio:device0/in_voltage0_raw' +}); +``` -## Class: ADCPin +## Class: AdcPin -### adcpin.read([callback]) +### adcpin.read(callback) * `callback` {Function} * `err`: {Error|null} + * `{number}` Analog value. Reads the analog value from the pin asynchronously. @@ -73,7 +87,7 @@ adc0.read(function(err, value) { ### adcpin.readSync() -* Returns: `{int}` Analog value. +* Returns: `{number}` Analog value. Reads the analog value from the pin synchronously. diff --git a/docs/api/IoT.js-API-Assert.md b/docs/api/IoT.js-API-Assert.md index 1c522cea51..8459f66779 100644 --- a/docs/api/IoT.js-API-Assert.md +++ b/docs/api/IoT.js-API-Assert.md @@ -2,16 +2,16 @@ The following shows Assert module APIs available for each platform. -| | Linux
(Ubuntu) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | -| :---: | :---: | :---: | :---: | -| assert.assert | O | O | O | -| assert.doesNotThrow | O | O | O | -| assert.equal | O | O | O | -| assert.fail | O | O | O | -| assert.notEqual | O | O | O | -| assert.notStrictEqual | O | O | O | -| assert.strictEqual | O | O | O | -| assert.throws | O | O | O | +| | Linux
(Ubuntu) | Tizen
(Raspberry Pi) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | TizenRT
(Artik053) | +| :---: | :---: | :---: | :---: | :---: | :---: | +| assert.assert | O | O | O | O | O | +| assert.doesNotThrow | O | O | O | O | O | +| assert.equal | O | O | O | O | O | +| assert.fail | O | O | O | O | O | +| assert.notEqual | O | O | O | O | O | +| assert.notStrictEqual | O | O | O | O | O | +| assert.strictEqual | O | O | O | O | O | +| assert.throws | O | O | O | O | O | # Assert diff --git a/docs/api/IoT.js-API-BLE.md b/docs/api/IoT.js-API-BLE.md index a51116d430..17554e3cce 100644 --- a/docs/api/IoT.js-API-BLE.md +++ b/docs/api/IoT.js-API-BLE.md @@ -2,11 +2,11 @@ The following shows BLE module APIs available for each platform. -| | Linux
(Ubuntu) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | -| :---: | :---: | :---: | :---: | -| ble.startAdvertising | O | O | X | -| ble.stopAdvertising | O | O | X | -| ble.setServices | O | O | X | +| | Linux
(Ubuntu) | Tizen
(Raspberry Pi) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | TizenRT
(Artik053) | +| :---: | :---: | :---: | :---: | :---: | :---: | +| ble.startAdvertising | O | X | O | X | X | +| ble.stopAdvertising | O | X | O | X | X | +| ble.setServices | O | X | O | X | X | # BLE - Bluetooth Low Energy diff --git a/docs/api/IoT.js-API-Buffer.md b/docs/api/IoT.js-API-Buffer.md index 85caf403b0..deca9eeed7 100644 --- a/docs/api/IoT.js-API-Buffer.md +++ b/docs/api/IoT.js-API-Buffer.md @@ -2,21 +2,22 @@ The following shows Buffer module APIs available for each platform. -| | Linux
(Ubuntu) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | -| :---: | :---: | :---: | :---: | -| buf.compare | O | O | O | -| buf.copy | O | O | O | -| buf.equals | O | O | O | -| buf.fill | O | O | O | -| buf.slice | O | O | O | -| buf.toString | O | O | O | -| buf.write | O | O | O | -| buf.writeUInt8 | O | O | O | -| buf.writeUInt16LE | O | O | O | -| buf.writeUInt32LE | O | O | O | -| buf.readInt8 | O | O | O | -| buf.readUInt8 | O | O | O | -| buf.readUInt16LE | O | O | O | +| | Linux
(Ubuntu) | Tizen
(Raspberry Pi) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | TizenRT
(Artik053) | +| :---: | :---: | :---: | :---: | :---: | :---: | +| buf.compare | O | O | O | O | O | +| buf.copy | O | O | O | O | O | +| buf.equals | O | O | O | O | O | +| buf.fill | O | O | O | O | O | +| buf.from | O | O | O | O | O | +| buf.slice | O | O | O | O | O | +| buf.toString | O | O | O | O | O | +| buf.write | O | O | O | O | O | +| buf.writeUInt8 | O | O | O | O | O | +| buf.writeUInt16LE | O | O | O | O | O | +| buf.writeUInt32LE | O | O | O | O | O | +| buf.readInt8 | O | O | O | O | O | +| buf.readUInt8 | O | O | O | O | O | +| buf.readUInt16LE | O | O | O | O | O | # Buffer @@ -33,15 +34,16 @@ UInt8Array in the future. var Buffer = require('buffer'); // Creates a zero-filled Buffer of length 10. -var buf1 = Buffer(10); +var buf1 = new Buffer(10); // Creates a Buffer containing [0x1, 0x2, 0x3]. -var buf2 = Buffer([1, 2, 3]); +var buf2 = new Buffer([1, 2, 3]); // Creates a Buffer containing UTF-8 bytes [0x74, 0xc3, 0xa9, 0x73, 0x74]. -var buf3 = Buffer('tést'); +var buf3 = new Buffer('tést'); ``` +## Class: Buffer ### new Buffer(size) * `size` {integer} Size of the new buffer. @@ -87,22 +89,22 @@ and these pairs are converted to bytes. ```js var Buffer = require('buffer'); -var buffer = new Buffer(String.fromCharCode(65)) +var buffer = new Buffer(String.fromCharCode(65)); // prints: 1 console.log(buffer); -var buffer = new Buffer(String.fromCharCode(128)) +var buffer = new Buffer(String.fromCharCode(128)); // prints: 2 console.log(buffer); -var buffer = new Buffer(String.fromCharCode(2048)) +var buffer = new Buffer(String.fromCharCode(2048)); // prints: 3 console.log(buffer); -var buffer = new Buffer('4142', 'hex') +var buffer = new Buffer('4142', 'hex'); // prints: AB console.log(buffer); @@ -119,7 +121,7 @@ numbers are converted to integers first and their modulo **Example** ```js -var buffer = new Buffer([65, 256 + 65, 65 - 256, 65.1]) +var buffer = new Buffer([65, 256 + 65, 65 - 256, 65.1]); // prints: AAAA console.log(buffer); @@ -181,6 +183,84 @@ console.log(buffer); ``` +### Buffer.from(array) +* `array` {Array} Array of numbers. +* Returns: {Buffer} containing the elements from `array` + +Creates a new Buffer from an array of numbers. The numbers are converted to integers first and their modulo 256 remainder is used for constructing the buffer. + +**Example** + +```js +var Buffer = require('buffer'); + +var source = new Buffer[65, 66, 67]; +var buffer = Buffer.from(source); + +//prints: ABC +console.log(buffer.toString()); +``` + + +### Buffer.from(string[,encoding]) +* `str` {String} Source string. +* `encoding` {String} Encoding format. +* Returns: {Buffer} containing the elements from `str` + +Creates a new buffer which contains the CESU-8 representation of the str string argument. If encoding optional argument is present its value must be hex. When this encoding is specified the str argument must be a sequence of hexadecimal digit pairs, and these pairs are converted to bytes. + +**Example** + +```js +var Buffer = require('buffer'); + +var buffer = Buffer.from('4142','hex'); + +//prints: AB +console.log(buffer.toString()); +``` + + +### Buffer.from(buffer) +* `buffer` {Buffer} Source buffer. +* Returns: {Buffer} which is the copy of `buffer` +Creates a copy of an existing buffer. The buffer data is not shared between the two buffers. + +**Example** + +```js +var Buffer = require('buffer'); + +var source = new Buffer(12); +var buffer = Buffer.from(source); +``` + + +### Buffer.from(arrayBuffer[, byteOffset[, length]]) +* `arrayBuffer` {ArrayBuffer} Arraybuffer, or a buffer of a TypedArray +* `byteOffset` {Number} Index of first byte to expose. Default: 0. +* `length` {Number} Number of bytes to expose. Default: arrayBuffer.length - byteOffset. +* Returns: {Buffer} containing the data of `arraybuffer` from read `offset` with `length` + +**Example** + +```js +var source = new ArrayBuffer(12); +var buffer = Buffer.from(source, 0, 2); + +//prints: 2 +console.log(buffer.length); +``` + +```js +var typed_source = new Uint8Array([65,66]); +var arr_buff = Buffer.from(typed_source1.buffer, 0, 2); + +//prints: AB +console.log(buff.toString('utf-8')); +``` + + ### Buffer.isBuffer(obj) * `obj` {Object} * Returns: {boolean} @@ -214,7 +294,7 @@ this value. ```js var Buffer = require('buffer'); -var buffer = new Buffer([0xc8, 0x80]) +var buffer = new Buffer([0xc8, 0x80]); // prints: 2 console.log(buffer.length); diff --git a/docs/api/IoT.js-API-Crypto.md b/docs/api/IoT.js-API-Crypto.md new file mode 100644 index 0000000000..bdaea8c7ca --- /dev/null +++ b/docs/api/IoT.js-API-Crypto.md @@ -0,0 +1,93 @@ +### Platform Support + +The following chart shows the availability of each Crypto module API function on each platform. + +| | Linux
(Ubuntu) | Tizen
(Raspberry Pi) | Raspbian
(Raspberry Pi) | Nuttx
(STM32F4-Discovery) | TizenRT
(Artik053) | +| :---: | :---: | :---: | :---: | :---: | :---: | +| crypto.createHash | O | O | O | O | O | +| crypto.createVerify | O | O | O | O | O | +| crypto.getHashes | O | O | O | O | O | + +# Crypto + +The module provides limited cryptographic functionality, namely hashing and signature verification. +To access this module use `require('crypto')`. + +### crypto.createVerify(hashType) +Creates and returns a `Verify` object. This object can not be created with the `new` keyword. + - `hashType` {string} Hash type of the signature. {`sha1 | sha256`} + +Note: We currently only support `rsa-sha1` and `rsa-sha256` signatures. + +### crypto.createHash(hashType) +Creates and returns a `Hash` object. This object can not be created with the `new` keyword. + - `hashType` {string} Type of the hash. {`sha1 | sha256`} + +Note: We currently only support `sha1` and `sha256` hashes. + +### crypto.getHashes() +Returns the available hashing methods. + +## Class: Verify +The `Verify` class allows the user to verify a signature against a public key. + +### verify.update(data) +Updates the `Verify` object with the given `data`. + - `data` {Buffer | string} Updates the object with the `data`. If there is already `data` in the object, concatenates them. + +**Example** +```js +var crypto = require('crypto'); +var myVerifyObject = crypto.createVerify('sha256'); + +myVerifyObject.update('This data should be verified'); +myVerifyObject.update('\nAnd this belongs there too.'); +``` + +### verify.verify(publicKey, signature) +Verifies the `signature` against the `publicKey` using the `data` added with `verify.update()`. + - `publicKey` {string | Buffer} A valid RSA Public key. + - `signature` {string | Buffer} A base64 encoded `rsa-sha1` or `rsa-sha256` signature. + +Returns `true` if the verification succeeds, `false` otherwise. + +**Example** +```js +var crypto = require('crypto'); + +var myVerifyObject = crypto.createVerify('sha256'); +var myKey = getPublicKeySomehow(); +var myData = getSomeStringToVerify(); +var mySignature = getSignatureSomehow(); + + +myVerifyObject.update(myData); +var success = myVerifyObject.verify(myKey, mySignature); + +if (!success) { + throw new Error('Invalid signature !'); +} +``` + +## Class: Hash +The `Hash` class creates hashes from the data given. + +### hash.update(data) +Updates the `Hash` object with the given `data`. + - `data` {Buffer | String} Updates the object with the `data`. If there is already `data` in the object, concatenates them. + +### hash.digest(encoding) +Returns an `encoded` hash of the input `data` as a `string` or `Buffer`. + - `encoding` {string} Encodes the result of the hashing to the given format. Can be {`hex | base64`}. If no `encoding` is given, or the given `encoding` doesn't match the known formats, returns the raw `hash` in a `Buffer`. + +Digest can only be called once on a given `Hash` object. + +**Example** +```js +var crypto = require('crypto'); + +var myData = 'Some data to hash'; +var myHashObj = crypto.createHash('sha1'); +myHashObj.update(myData); +var myHash = myHashObj.digest('hex'); +``` diff --git a/docs/api/IoT.js-API-DGRAM.md b/docs/api/IoT.js-API-DGRAM.md index 26d9799884..4f982dc075 100644 --- a/docs/api/IoT.js-API-DGRAM.md +++ b/docs/api/IoT.js-API-DGRAM.md @@ -2,21 +2,21 @@ The following shows dgram module APIs available for each platform. -| | Linux
(Ubuntu) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | -| :---: | :---: | :---: | :---: | -| dgram.createSocket | O | O | △ ¹ | -| dgram.Socket.addMembership | O | O | X | -| dgram.Socket.address | O | O | X | -| dgram.Socket.bind | O | O | △ ¹ | -| dgram.Socket.close | O | O | △ ² | -| dgram.Socket.dropMembership | O | O | X | -| dgram.Socket.send | O | O | △ ¹ | -| dgram.Socket.setBroadcast | O | O | X | -| dgram.Socket.setMulticastLoopback | O | O | X | -| dgram.Socket.setMulticastTTL | X | X | X | -| dgram.Socket.setTTL | O | O | X | - -1. On NuttX/STM32F4-Discovery, even a couple of sockets/server/requests might not work properly. +| | Linux
(Ubuntu) | Tizen
(Raspberry Pi) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | TizenRT
(Artik053) | +| :---: | :---: | :---: | :---: | :---: | :---: | +| dgram.createSocket | O | O | O | △ ¹ | △ ¹ | +| dgram.Socket.addMembership | O | X | O | X | O | +| dgram.Socket.address | O | O | O | X | O | +| dgram.Socket.bind | O | O | O | △ ¹ | △ ¹ | +| dgram.Socket.close | O | O | O | △ ² | O | +| dgram.Socket.dropMembership | O | X | O | X | O | +| dgram.Socket.send | O | O | O | △ ¹ | △ ¹ | +| dgram.Socket.setBroadcast | O | X | O | X | X | +| dgram.Socket.setMulticastLoopback | O | O | O | X | O | +| dgram.Socket.setMulticastTTL | X | X | X | X | O | +| dgram.Socket.setTTL | O | X | O | X | O | + +1. On NuttX/STM32F4-Discovery and TizenRT/Artik053, even a couple of sockets/server/requests might not work properly. 2. On NuttX/STM32F4-Discovery, close() may block due to a bug in poll(). diff --git a/docs/api/IoT.js-API-DNS.md b/docs/api/IoT.js-API-DNS.md index fb1a70c7b9..0a01781a86 100644 --- a/docs/api/IoT.js-API-DNS.md +++ b/docs/api/IoT.js-API-DNS.md @@ -2,9 +2,9 @@ The following shows dns module APIs available for each platform. -| | Linux
(Ubuntu) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | -| :---: | :---: | :---: | :---: | -| dns.lookup | O | O | X | +| | Linux
(Ubuntu) | Tizen
(Raspberry Pi) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | TizenRT
(Artik053) | +| :---: | :---: | :---: | :---: | :---: | :---: | +| dns.lookup | O | O | O | X | O | ※ dns.lookup currently only returns IPv4 addresses. Support for IPv6 addresses are on the roadmap. @@ -27,7 +27,7 @@ Returned address types are determined by the types of addresses supported by the ### dns.V4MAPPED * `{number}` -If the IPv6 family was specified, but no IPv6 addresses were found, then return IPv4 mapped IPv6 addresses. +If the IPv6 family was specified, but no IPv6 addresses were found, then return IPv4 mapped IPv6 addresses. diff --git a/docs/api/IoT.js-API-Events.md b/docs/api/IoT.js-API-Events.md index 2bbf198687..edb85e6ea4 100644 --- a/docs/api/IoT.js-API-Events.md +++ b/docs/api/IoT.js-API-Events.md @@ -2,14 +2,14 @@ The following shows Event module APIs available for each platform. -| | Linux
(Ubuntu) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | -| :---: | :---: | :---: | :---: | -| emitter.addListener | O | O | O | -| emitter.on | O | O | O | -| emitter.emit | O | O | O | -| emitter.once | O | O | O | -| emitter.removeListener | O | O | O | -| emitter.removeAllListeners | O | O | O | +| | Linux
(Ubuntu) | Tizen
(Raspberry Pi) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | TizenRT
(Artik053) | +| :---: | :---: | :---: | :---: | :---: | :---: | +| emitter.addListener | O | O | O | O | O | +| emitter.on | O | O | O | O | O | +| emitter.emit | O | O | O | O | O | +| emitter.once | O | O | O | O | O | +| emitter.removeListener | O | O | O | O | O | +| emitter.removeAllListeners | O | O | O | O | O | # Events @@ -18,11 +18,11 @@ IoT.js is based on event-driven programming where objects (called "emitters") pe # Class: EventEmitter -The `events.EventEmitter` plays a role as base class for "emitters". -User application would not directly creates an instance of `EventEmitter` since `EventEmitter` is an abstract trait which defines its behavior and grants to sub-classes. +The `EventEmitter` plays a role as base class for "emitters". +User application would not directly create an instance of `EventEmitter` since `EventEmitter` is an abstract trait which defines its behavior and grants to sub-classes. ### new EventEmitter() -* Returns {events.EventEmitter}. +* Returns {EventEmitter}. Returns with a new EventEmitter object. @@ -31,7 +31,7 @@ Returns with a new EventEmitter object. ```js -var EventEmitter = require('events').EventEmitter; +var EventEmitter = require('events'); var emitter = new EventEmitter(); @@ -42,7 +42,7 @@ var emitter = new EventEmitter(); * `event` {string} The name of the event. * `listener` {Function} The callback function. * `args` {any}. -* Returns `emitter` {events.EventEmitter}. +* Returns `emitter` {EventEmitter}. It is an alias for `emitter.on(eventName, listener)`. @@ -53,7 +53,7 @@ In case of multiple calls the `listener` will be added and called multiple times ```js -var EventEmitter = require('events').EventEmitter; +var EventEmitter = require('events'); var emitter = new EventEmitter(); @@ -75,7 +75,7 @@ console.log(eventSequence); // prints '22' * `event` {string} The name of the event. * `listener` {Function} The callback function. * `args` {any}. -* Returns `emitter` {events.EventEmitter}. +* Returns `emitter` {EventEmitter}. Adds the `listener` callback function to the end of the listener's list for the given `event`. No checks are made to see if the `listener` has already been added. In case of multiple calls the `listener` will be added and called multiple times. @@ -84,7 +84,7 @@ In case of multiple calls the `listener` will be added and called multiple times ```js -var EventEmitter = require('events').EventEmitter; +var EventEmitter = require('events'); var emitter = new EventEmitter(); emitter.on('event', function() { @@ -108,7 +108,7 @@ Returns true if the event had listeners, false otherwise. ```js -var EventEmitter = require('events').EventEmitter; +var EventEmitter = require('events'); var emitter = new EventEmitter(); emitter.addListener('event', function() { @@ -125,7 +125,7 @@ emitter.emit('not_an_event'); // false * `event` {string} The name of the event. * `listener` {Function} The callback function. * `args` {any}. -* Returns `emitter` {events.EventEmitter}. +* Returns `emitter` {EventEmitter}. Adds the `listener` as a one time listener for the `event`. @@ -136,7 +136,7 @@ The listener will be invoked only once, when the first `event` is emitted. ``` js -var EventEmitter = require('events').EventEmitter; +var EventEmitter = require('events'); var assert = require('assert'); var emitter = new EventEmitter(); @@ -159,7 +159,7 @@ assert.equal(onceCnt, 1); * `event` {string} The name of the event. * `listener` {Function} The callback function. * `args` {any}. -* Returns `emitter` {events.EventEmitter}. +* Returns `emitter` {EventEmitter}. Removes `listener` from the list of event listeners. @@ -169,7 +169,7 @@ If you add the same `listener` multiple times, this removes only one instance of ```js -var EventEmitter = require('events').EventEmitter; +var EventEmitter = require('events'); var emitter = new EventEmitter(); var listener = function() { @@ -183,7 +183,7 @@ emitter.removeListener('event', listener); ### emitter.removeAllListeners([event]) * `event` {string} The name of the event. -* Returns `emitter` {events.EventEmitter}. +* Returns `emitter` {EventEmitter}. Removes all listeners. @@ -193,7 +193,7 @@ If `event` was specified, it only removes the listeners for that event. ``` js -var EventEmitter = require('events').EventEmitter; +var EventEmitter = require('events'); var emitter = new EventEmitter(); diff --git a/docs/api/IoT.js-API-File-System.md b/docs/api/IoT.js-API-File-System.md index 2e58633871..7bd59cff68 100644 --- a/docs/api/IoT.js-API-File-System.md +++ b/docs/api/IoT.js-API-File-System.md @@ -2,36 +2,38 @@ The following shows fs module APIs available for each platform. -| | Linux
(Ubuntu) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | -| :---: | :---: | :---: | :---: | -| fs.close | O | O | O | -| fs.closeSync | O | O | O | -| fs.exists | O | O | O | -| fs.existsSync | O | O | O | -| fs.fstat | O | O | X | -| fs.fstatSync | O | O | X | -| fs.mkdir | O | O | O | -| fs.mkdirSync | O | O | O | -| fs.open | O | O | O | -| fs.openSync | O | O | O | -| fs.read | O | O | O | -| fs.readSync | O | O | O | -| fs.readdir | O | O | X | -| fs.readdirSync | O | O | X | -| fs.readFile | O | O | O | -| fs.readFileSync | O | O | O | -| fs.rename | O | O | O | -| fs.renameSync | O | O | O | -| fs.rmdir | O | O | O | -| fs.rmdirSync | O | O | O | -| fs.stat | O | O | O | -| fs.statSync | O | O | O | -| fs.unlink | O | O | O | -| fs.unlinkSync | O | O | O | -| fs.write | O | O | O | -| fs.writeSync | O | O | O | -| fs.writeFile | O | O | O | -| fs.writeFileSync | O | O | O | +| | Linux
(Ubuntu) | Tizen
(Raspberry Pi) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | TizenRT
(Artik053) | +| :---: | :---: | :---: | :---: | :---: | :---: | +| fs.close | O | O | O | O | O | +| fs.closeSync | O | O | O | O | O | +| fs.createReadStream | O | O | O | O | O | +| fs.createWriteStream | O | O | O | O | O | +| fs.exists | O | O | O | O | O | +| fs.existsSync | O | O | O | O | O | +| fs.fstat | O | O | O | X | X | +| fs.fstatSync | O | O | O | X | X | +| fs.mkdir | O | O | O | O | O | +| fs.mkdirSync | O | O | O | O | O | +| fs.open | O | O | O | O | O | +| fs.openSync | O | O | O | O | O | +| fs.read | O | O | O | O | O | +| fs.readSync | O | O | O | O | O | +| fs.readdir | O | O | O | O | O | +| fs.readdirSync | O | O | O | O | O | +| fs.readFile | O | O | O | O | O | +| fs.readFileSync | O | O | O | O | O | +| fs.rename | O | O | O | O | O | +| fs.renameSync | O | O | O | O | O | +| fs.rmdir | O | O | O | O | O | +| fs.rmdirSync | O | O | O | O | O | +| fs.stat | O | O | O | O | O | +| fs.statSync | O | O | O | O | O | +| fs.unlink | O | O | O | O | O | +| fs.unlinkSync | O | O | O | O | O | +| fs.write | O | O | O | O | O | +| fs.writeSync | O | O | O | O | O | +| fs.writeFile | O | O | O | O | O | +| fs.writeFileSync | O | O | O | O | O | ※ On NuttX path should be passed with a form of **absolute path**. @@ -112,6 +114,168 @@ fs.closeSync(fd); ``` +## Class: fs.ReadStream + +A successful call to `fs.createReadStream()` will return a new `fs.ReadStream` +object. + +`fs.ReadStream` inherits from `stream.Readable`. + + +### Event: 'open' +* `fd` {integer} File descriptor used by the `fs.ReadStream`. + +Emitted when the `fs.ReadStream`'s file descriptor has been opened. + + +### Event: 'ready' + +Emitted when the `fs.ReadStream` is ready to be used. Emitted immediately +after `open`. + + +### Event: 'data' +* `chunk` {Buffer|string} + +Inherited from `stream.Readable`. Emitted when the stream passes the ownership +of the data to a consumer. Only streams in flowing mode emit this event. + +A stream can be switched to flowing mode by calling the readable.resume() +function or by adding a 'data' event handler. + + +### Event: 'close' + +Emitted when the `fs.ReadStream`'s file descriptor has been closed. + + +### ReadStream.bytesRead +* {integer} + +Number of bytes that have been read so far. + + +### ReadStream.path +* {string} + +The path to the file of the `fs.ReadStream`. + + +### fs.createReadStream(path[, options]) +* `path` {string} File path to open for reading. +* `options` {Object} + * `flags` {string} Flags to open file with. **Default:** `'r'` + * `encoding` {string} **Default:** `null` + * `fd` {integer} File descriptor to be used. **Default:** `null` + * `mode` {integer} Permission mode. **Default:** `0666` + * `autoClose` {boolean} Should the file be closed automatically. **Default:** `true` + * `bufferSize` {integer} Size of buffer in bytes. **Default:** `4096` +* Returns: `fs.ReadStream` + +If `fd` is specified, `path` will be ignored and the specified file +descriptor will be used instead. + +If `autoClose` is `false`, the file will not be closed automatically, +even if there is an error, it will be the application's responsibility. +If it is `true` (as by default), the file will be closed automatically +when end of file is reached or the stream ends. + +**Example** + +```js +var fs = require('fs'); + +var rStream = fs.createReadStream('example.txt'); +rStream.on('data', function(data) { + console.log(data.toString()); +}); +``` + +`fs.ReadStream` inherits from `stream.Readable`, so it is possible to pipe +it into any `stream.Writable`. + +**Example** + +```js +var fs = require('fs'); + +var readableFileStream = fs.createReadStream('in.txt'); +var writableFileStream = fs.createWriteStream('out.txt'); + +// The content of in.txt will be copied to out.txt +readableFileStream.pipe(writableFileStream); +``` + + +## Class: fs.WriteStream + +A successful call to `fs.createWriteStream()` will return a new `fs.WriteStream` +object. + +`fs.WriteStream` inherits from `stream.Writable`. + + +### Event: 'open' +* `fd` {integer} File descriptor used by the `fs.WriteStream`. + +Emitted when the `fs.WriteStream`'s file descriptor has been opened. + + +### Event: 'ready' + +Emitted when the `fs.WriteStream` is ready to be used. Emitted immediately +after `open`. + + +### Event: 'close' + +Emitted when the `fs.WriteStream`'s file descriptor has been closed. + + +### WriteStream.bytesWritten + +The number of bytes written so far. Does not include data that is still queued +for writing. + + +### WriteStream.path + +The path to the file of the `fs.WriteStream`. + + +### fs.createWriteStream +* `path` {string} File path to be opened for writing. +* `options` {Object} + * `flags` {string} Flags to open the file with. **Default:** `'w'` + * `fd` {integer} File descriptor to be used. **Default:** `null` + * `mode` {integer} Permission mode. **Default:** `0666` + * `autoClose` {boolean} Should the file be closed automatically. **Default:** `true` +* Returns `fs.WriteStream` + +Works similarly to `fs.createReadStream()`, but returns an `fs.WriteStream`. + +If `fd` is specified, `path` will be ignored and the specified file +descriptor will be used instead. + +If `autoClose` is `false`, the file will not be closed automatically, +even if there is an error, it will be the application's responsibility. +If it is `true` (as by default), the file will be closed automatically +when end of file is reached or the stream ends. + +**Example** + +```js +var fs = require('fs'); + +var wStream = fs.createWriteStream('example.txt'); + +wStream.on('ready', function() { + wStream.write('test data'); + // 'test data' will be written into example.txt +}); +``` + + ### fs.exists(path, callback) * `path` {string} File path to be checked. * `callback` {Function} diff --git a/docs/api/IoT.js-API-GPIO.md b/docs/api/IoT.js-API-GPIO.md index fe71013ed5..3db7598a2c 100644 --- a/docs/api/IoT.js-API-GPIO.md +++ b/docs/api/IoT.js-API-GPIO.md @@ -2,15 +2,17 @@ The following shows GPIO module APIs available for each platform. -| | Linux
(Ubuntu) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | -| :---: | :---: | :---: | :---: | -| gpio.open | O | O | O | -| gpiopin.write | O | O | O | -| gpiopin.writeSync | O | O | O | -| gpiopin.read | △ | △ | O | -| gpiopin.readSync | O | O | O | -| gpiopin.close | O | O | O | -| gpiopin.closeSync | O | O | O | +| | Linux
(Ubuntu) | Tizen
(Raspberry Pi) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | TizenRT
(Artik053) | +| :---: | :---: | :---: | :---: | :---: | :---: | +| gpio.open | X | O | O | O | O | +| gpio.openSync | X | O | O | O | O | +| gpiopin.setDirectionSync | X | O | O | O | O | +| gpiopin.write | X | O | O | O | O | +| gpiopin.writeSync | X | O | O | O | O | +| gpiopin.read | X | O | O | O | O | +| gpiopin.readSync | X | O | O | O | O | +| gpiopin.close | X | O | O | O | O | +| gpiopin.closeSync | X | O | O | O | O | # GPIO @@ -23,16 +25,11 @@ 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) -## Class: GPIO - -### new GPIO() - -Returns a new GPIO object which can access any GPIO pins. ### DIRECTION * `IN` Input pin. @@ -51,48 +48,96 @@ direction of the pin. * `OPENDRAIN` Open drain (pin direction must be [`OUT`](#direction)). An enumeration which can be used to specify the -configuration of the pin. +mode of the pin. These options are only supported on NuttX. + + +### EDGE +* `NONE` None. +* `RISING` Rising. +* `FALLING` Falling. +* `BOTH` Both. + +An enumeration which can be used to specify the +edge of the pin. -### gpio.open(configuration[, callback]) -* `configuration` {Object} +### gpio.open(configuration, callback) +* `configuration` {Object} Configuration for open GPIOPin. * `pin` {number} Pin number. Mandatory field. - * `direction` {GPIO.DIRECTION} Pin direction. **Default:** `GPIO.DIRECTION.OUT` - * `mode` {GPIO.MODE} Pin mode. **Default:** `GPIO.MODE.NONE` + * `direction` {[gpio.DIRECTION](#direction)} Pin direction. **Default:** `gpio.DIRECTION.OUT` + * `mode` {[gpio.MODE](#mode)} Pin mode. **Default:** `gpio.MODE.NONE` + * `edge` {[gpio.EDGE](#edge)} Pin edge. **Default:** `gpio.EDGE.NONE` * `callback` {Function} * `error` {Error|null} -* Returns: {GPIOPin} - -Opens the specified GPIO pin and sets the pin configuration. + * `gpioPin` {Object} An instance of GPIOPin. +* Returns: {Object} An instance of GPIOPin. -The mode argument is ignored on Linux. +Get GPIOPin object with configuration asynchronously. -The optional `callback` function will be called after +The `callback` function will be called after opening is completed. The `error` argument is an `Error` object on failure or `null` otherwise. **Example** ```js -var GPIO = require('gpio'); -var gpio = new GPIO(); +var gpio = require('gpio'); var gpio10 = gpio.open({ pin: 10, direction: gpio.DIRECTION.OUT, - mode: gpio.MODE.NONE -}, function(err) { + mode: gpio.MODE.PUSHPULL, + edge: gpio.EDGE.RISING +}, function(err, pin) { if (err) { throw err; } }); ``` +### gpio.openSync(configuration) +* `configuration` {Object} Configuration for open GPIOPin. + * `pin` {number} Pin number. Mandatory field. + * `direction` {[gpio.DIRECTION](#direction)} Pin direction. **Default:** `gpio.DIRECTION.OUT` + * `mode` {[gpio.MODE](#mode)} Pin mode. **Default:** `gpio.MODE.NONE` + * `edge` {[gpio.EDGE](#edge)} Pin edge. **Default:** `gpio.EDGE.NONE` +* Returns: {Object} An instance of GPIOPin. + +Get GPIOPin object with configuration synchronously. + +**Example** + +```js +var gpio = require('gpio'); + +var gpio10 = gpio.openSync({ + pin: 10, + direction: gpio.DIRECTION.IN, + mode: gpio.MODE.PULLUP +}); +``` + + ## Class: GPIOPin This class represents an opened and configured GPIO pin. It allows getting and setting the status of the pin. +### gpiopin.setDirectionSync(direction) + * `direction` {[gpio.DIRECTION](#direction)} Pin direction. + +Set the direction of a GPIO pin. + +**Example** + +```js +gpio10.setDirectionSync(gpio.DIRECTION.OUT); +gpio10.writeSync(1); + +gpio10.setDirectionSync(gpio.DIRECTION.IN); +var value = gpio10.readSync(); +``` + ### gpiopin.write(value[, callback]) * `value` {number|boolean} * `callback` {Function} @@ -192,7 +237,7 @@ gpio10.close(function(err) { ### gpiopin.closeSync() -Closes a GPIO pin. +Synchronously closes a GPIO pin. **Example** diff --git a/docs/api/IoT.js-API-HTTP-Signature.md b/docs/api/IoT.js-API-HTTP-Signature.md new file mode 100644 index 0000000000..eab7fbf892 --- /dev/null +++ b/docs/api/IoT.js-API-HTTP-Signature.md @@ -0,0 +1,40 @@ +### Platform Support + +The following chart shows the availability of each HTTP Signature module API function on each platform. + +| | Linux
(Ubuntu) | Tizen
(Raspberry Pi) | Raspbian
(Raspberry Pi) | Nuttx
(STM32F4-Discovery) | TizenRT
(Artik053) | +| :---: | :---: | :---: | :---: | :---: | :---: | +| httpSignature.parseRequest | O | O | O | O | O | +| httpSignature.verify | O | O | O | O | O | + +# HTTP Signature +The module makes it possible to verify the signature on HTTP Requests as stated in the RFC Standard (https://tools.ietf.org/html/draft-cavage-http-signatures-10). + +### httpSignature.parseRequest(request) +Parses an `HTTP request` and returns with the parsed object. + - `request` {Object} A valid `HTTP Request` + +The returned object can be used to later to `verify` the `signature` of the `request`. + +### httpSignature.verify(parsedRequest, publicKey) +Verifies the `parsedRequest`'s `signature` against the given `publicKey`. Returns `true` if the verification succeeds, `false` otherwise. + - `parsedRequest` {Object} An `HTTP Request` parsed by `httpSignature.parseRequest()` function. + - `publicKey` {Buffer | string} The RSA Public key. + +**Example** +```js +var httpSign = require('http_signature'); + +... + +function myHTTPListener(req, res) { + var parsedRequest = httpSign.parseRequest(req); + if (!httpSign.verify(parsedRequest)) + // Verification failed + return res.send(401); + } + + // Signature is OK, handle the request normally + requestHandler(req, res); +} +``` diff --git a/docs/api/IoT.js-API-HTTP.md b/docs/api/IoT.js-API-HTTP.md index 1d02ef872e..3540ef7fce 100644 --- a/docs/api/IoT.js-API-HTTP.md +++ b/docs/api/IoT.js-API-HTTP.md @@ -2,34 +2,90 @@ The following shows Http module APIs available for each platform. - | | Linux
(Ubuntu) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | - | :---: | :---: | :---: | :---: | - | http.createServer | O | O | △ ¹ | - | http.request | O | O | △ ¹ | - | http.get | O | O | △ ¹ | - -1. On NuttX/STM32F4-Discovery, even a couple of sockets/server/requests might not work properly. + | | Linux
(Ubuntu) | Tizen
(Raspberry Pi) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | TizenRT
(Artik053) | + | :--- | :---: | :---: | :---: | :---: | :---: | + | http.createServer | O | O | O | △ ¹ | △ ¹ | + | http.request | O | O | O | △ ¹ | △ ¹ | + | http.get | O | O | O | △ ¹ | △ ¹ | + | http.METHODS | O | O | O | O | O | + | http.Server | O | O | O | △ ¹ | △ ¹ | + | http.Server.close | O | O | O | △ ¹ | △ ¹ | + | http.Server.listen | O | O | O | △ ¹ | △ ¹ | + | http.Server.setTimeout | O | O | O | △ ¹ | △ ¹ | + | http.ClientRequest | O | O | O | △ ¹ | △ ¹ | + | http.ClientRequest.abort | O | O | O | △ ¹ | △ ¹ | + | http.ClientRequest.end | O | O | O | △ ¹ | △ ¹ | + | http.ClientRequest.setTimeout | O | O | O | △ ¹ | △ ¹ | + | http.ClientRequest.write | O | O | O | △ ¹ | △ ¹ | + | http.IncomingMessage | O | O | O | △ ¹ | △ ¹ | + | http.IncomingMessage.headers | O | O | O | △ ¹ | △ ¹ | + | http.IncomingMessage.method | O | O | O | △ ¹ | △ ¹ | + | http.IncomingMessage.httpVersion | O | O | O | △ ¹ | △ ¹ | + | http.IncomingMessage.socket | O | O | O | △ ¹ | △ ¹ | + | http.IncomingMessage.statusCode | O | O | O | △ ¹ | △ ¹ | + | http.IncomingMessage.url | O | O | O | △ ¹ | △ ¹ | + | http.IncomingMessage.statusMessage | O | O | O | △ ¹ | △ ¹ | + | http.IncomingMessage.setTimeout | O | O | O | △ ¹ | △ ¹ | + | http.ServerResponse | O | O | O | △ ¹ | △ ¹ | + | http.ServerResponse.end | O | O | O | △ ¹ | △ ¹ | + | http.ServerResponse.getHeader | O | O | O | △ ¹ | △ ¹ | + | http.ServerResponse.setHeader | O | O | O | △ ¹ | △ ¹ | + | http.ServerResponse.setTimeout | O | O | O | △ ¹ | △ ¹ | + | http.ServerResponse.write | O | O | O | △ ¹ | △ ¹ | + | http.ServerResponse.writeHead | O | O | O | △ ¹ | △ ¹ | + +1. On NuttX/STM32F4-Discovery and TizenRT/Artik053, even a couple of sockets/server/requests might not work properly. # Http IoT.js provides HTTP to support HTTP server and client enabling users to receive/send HTTP request easily. -### http.createServer([requestListener]) +### http.createServer([options][, requestListener]) +* `options` {Object} + * `IncomingMessage` {Function} Specifies the `IncomingMessage` constructor to be used when creating an http incoming message object. + Useful when extending the original {http.IncommingMessge}. + Default: `http.IncommingMessage`. + * `ServerResponse` {Function} Specifies the `ServerResponse` constructor to be used when creating the server response object. + Useful when extending the original {http.ServerResponse}. + Default: 'http.ServerResponse`. * `requestListener` {Function} - * request {http.IncomingMessage} - * response {http.ServerResponse} + * `request` {http.IncomingMessage} + * `response` {http.ServerResponse} * Returns: {http.Server} -The `requestListener` is a function which is automatically added to the `'request'` event. +This call only creates the HTTP server instance and does not start the server. +To start the server and listen for connections use the `server.listen` method. + +If a server is no longer needed, all request and response streams should be closed and the `server.close` method +should be used to stop the server listening for connections. + +The `requestListener` is a function which is automatically added to the `'request'` event of the http server. **Example** ```js +var console = require('console'); +var http = require('http'); + var server = http.createServer(function(request, response) { - ... + console.log('Request for path: ' + request.url); + + var message = '

Hello

'; + + response.setHeader('Content-Type', 'text/html'); + response.setHeader('Content-Length', message.length); + response.writeHead(200); + response.write(message); + response.end(); +}); + +var port = 8081 +server.listen(port, function() { + console.log('HTTP server listening on port: ' + port); }); ``` + ### http.request(options[, callback]) * `options` {Object} * `host` {string} A domain name or IP address of the server to issue the request to. Defaults to 'localhost'. @@ -42,23 +98,32 @@ var server = http.createServer(function(request, response) { * `response` {http.IncomingMessage} * Returns: {http.ClientRequest} +The function creates a `http.ClientRequest` instance with the `options` defined. +This can be used to get data from a server or to send data for a server. + +In case of data send the `'Content-Length'` header should be specifed so the server can properly handle the request. + **Example** ```js var http = require('http'); +var data_A = 'Data to upload..'; +var data_B = 'more data'; var request = http.request({ method: 'POST', - port: 80, - headers: {'Content-Length': 3} + port: 8081, + headers: { 'Content-Length': data_A.length + data_B.length } }); -... +request.write(data_A); +request.write(data_B); request.end(); ``` -Note that in the example `req.end()` was called. With `http.request()` one must always call `req.end()` to signify that you're done with the request - even if there is no data being written to the request body. +Note that in the example `request.end()` was called. With `http.request()` one must always call +`request.end()` to signify that you're done with the request - even if there is no data being written to the request body. ### http.get(options[, callback]) * `options` {Object} @@ -66,7 +131,10 @@ Note that in the example `req.end()` was called. With `http.request()` one must * `response` {http.IncomingMessage} * Returns: {http.ClientRequest} -Same as `http.request` except that `http.get` automatically call `req.end()` at the end. +Same as `http.request` except that `http.get` automatically calls `request.end()` before returning the `http.ClientRequest` +instance thus calling the `write` method on the return value is invalid. + +This method is usefuly when there is no HTTP body to send. **Example** @@ -75,22 +143,29 @@ var http = require('http'); http.get({ port: 80, -}, function(res) { -... +}, function(response) { + console.log('Got response'); + response.on('data', function(chunk) { + console.log('Chunk: '); + console.log(chunk.toString()); + }); }); ``` ### http.METHODS -A list of HTTP methods supported by the parser as `string` properties of an `Object`. +* {string[]} + +A list of HTTP methods supported by the parser as a `string` array. ## Class: http.Server -This class inherits from `net.Server`. +This class inherits from `net.Server` and represents a HTTP server. ### Event: 'clientError' -* `exception` {Error} -* `socket` {net.Socket} +Event callback arguments: +* `exception` {Error} Describes what kind of error occured. +* `socket` {net.Socket} The socket which triggered the error. If a client connection emits an 'error' event, it will be forwarded here. Listener of this event is responsible for closing/destroying the underlying socket. @@ -113,62 +188,122 @@ server.listen(8000); ``` ### Event: 'close' -This event is emitted when server is closed. +This event is emitted when the HTTP server is closed. + +**Example** + +```js +var console = require('console'); +var http = require('http'); + +var server = http.createServer(); + +server.on('close', function() { + console.log('Server closed'); +}); + +server.listen(8081, function() { + console.log('HTTP server listening'); + + server.close(); +}); +``` + +When the example is executed the following will text will be printed: + +``` +HTTP server listening +Server closed +``` ### Event: 'connection' +Event callback argument: * `socket` {net.Socket} -This event is emitted when new TCP connection is established. +This event is emitted when new TCP connection is established. This event is triggered before +the `request` event. At this stage no HTTP header or data is processed. -### Event: 'connect' +Usually there is no need to listen for this event. -Emitted each time a client requests an `HTTP CONNECT` method. ### Event: 'request' -* `request` {http.IncomingMessage} -* `response` {http.ServerResponse} +* `request` {http.IncomingMessage} Represents the HTTP request sent by the client. +* `response` {http.ServerResponse} Represents the HTTP response which will be sent by the server. + +After HTTP request headers are parsed, the `'request'` event will be fired. + +**Example** + +```js +var console = require('console'); +var http = require('http'); + +var server = http.createServer(); + +server.on('request', function(request, response) { + console.log('Request for path: ' + request.url); -After request header is parsed, this event will be fired. + var message = '

Hello

'; + response.setHeader('Content-Type', 'text/html'); + response.setHeader('Content-Length', message.length); + response.writeHead(200); + response.write(message); + response.end(); +}); + +var port = 8081 +server.listen(port, function() { + console.log('HTTP server listening on port: ' + port); +}); +``` ### server.timeout +* {number} + The number of milliseconds of inactivity before a socket is presumed to have timed out. Default value is 120000 (2 minutes). ### server.listen(port[, hostname][, backlog][, callback]) -* `port` {number} -* `host` {string} -* `backlog` {number} -* `callback` {Function} +* `port` {number} Port number to listen on. +* `host` {string} Host IP or name where the server should listen. Default: `'0.0.0.0'`. +* `backlog` {number} The number of maximum pending connections. Default backlog length is 511 (not 512). +* `callback` {Function} Callback called when the `'listening'` event is emitted by the underlying `net.Server`. +* Returns {http.Server} The same server instance which was used to call the `listen` method. -Wait for new TCP connection with specified port and hostname. If no hostname is provided, server accepts any IP address. -`backlog` is maximum pending connections. Default backlog length is 511 (not 512). -`callback` will be called when server has been bound. +Wait for new TCP connections with specified port and hostname. If no hostname is provided, server listens on all available IP address. **Example** ```js +var console = require('console'); var http = require('http'); var server = http.createServer(function(req, res) { res.end(); }); -server.listen(8080, function() {}); +server.listen(8080, function() { + console.log('Started listening'); +}); ``` ### server.close([callback]) -* `callback` {Function} +* `callback` {Function} Function which to be registered for the `'close'` event. +* Returns {http.Server} The same server instance which was used to call the `close` method. -Stop accepting new connection to this server. However, the existing connections are preserved. When server is finally closed after all connections are closed, a callback is called. +Stop accepting new connections to this server. However, the existing connections are preserved. +When the server is finally closed after all connections was closed, the `'close'` event is triggered. -### server.setTimeout(ms, cb) +See the `'close`' event. + +### server.setTimeout(ms[, callback]) * `ms` {number} -* `cb` {Function} +* `callback` {Function} The callback function registered for the `'timeout'` event. -Registers cb for `'timeout'` event and sets socket's timeout value to ms. This event will be triggered by the underlying socket's 'timeout' event. +Registers cb for `'timeout'` event and sets socket's timeout value to ms. This event will be triggered by the underlying socket's `'timeout'` event. -If cb is not provided, the socket will be destroyed automatically after timeout. -If you provide cb, you should handle the socket's timeout. +If `callback` is not provided, the socket will be destroyed automatically after timeout. +If the `callback` function is provided, that function should should handle the socket's timeout. Default timeout for server is 2 minutes. @@ -184,73 +319,16 @@ server.setTimeout(100, function(socket) { }); ``` -## Class: http.ServerResponse - -### Event: 'close' -When underlying connection is closed, 'close' event is emitted. - -### Event: 'end' -This event is fired when no more data to be sent. - -### Event: 'finish' -This event is emitted when the response has been sent. It does not guarantee that client has received data yet. - - -### response.end([data][, callback]) -* `data` {Buffer | string} -* `callback` {Function} - -Finishes sending the response. - -If `data` is provided, it sends `data` first, and finishes. -If `callback` is specified, it is called when the response stream is finished. - -### response.getHeader(name) -* `name` {string} - -Returns `name` field of response's header - -### response.removeHeader(name) -* `name` {string} - -Removes `name` field from response's header - -### response.setHeader(name, value) -* `name` {string} -* `value` {string} - -Sets response's header field(`name`) to `value`. If the field exists, it overwrites the existing value. - -### response.setTimeout(ms, cb) - -* `ms` {number} -* `cb` {Function} - -Registers cb for 'timeout' event and set socket's timeout value to ms. This event will be triggered by the underlying socket's 'timeout' event. - -### response.write(data[, callback]) -* `data` {Buffer | string} -* `callback` {Function} - -Sends `data` as a response body. `callback` will be called when data is flushed. - -### response.writeHead(statusCode[, statusMessage][, headers]) -* `statusCode` {number} -* `statusMessage` {string} -* `headers` {Object} - -Sets response's header. `headers` is a map between field and value in header. - ## Class: http.ClientRequest -This object is created internally and returned from http.request(). It represents an in-progress request whose header has already been queued. +This object is created internally and returned from `http.request()`. It represents an in-progress request whose headers have already been queued. ### Event: 'close' This event is fired when the underlying socket is closed. ### Event: 'error' -* `callback` {Function} +Event callback arguments: * `err` {Error} Emitted if something went wrong with making or parsing the request. @@ -259,72 +337,206 @@ Emitted if something went wrong with making or parsing the request. This event is emitted after all the data was sent, meaning header and body all finished sending. ### Event: 'response' -* `response` {http.IncomingMessage} +Event callback arguments: +* `response` {http.IncomingMessage} The incoming HTTP response from the server. + +This event is emitted when server's HTTP response header is parsed. +The event is called only once. The developer should attach at least one event handler for this event +to correctly process any data sent back by the target server. -This event is emitted when server's response header is parsed. ` http.IncomingMessage` object is passed as argument to handler. +**Example** + +```js +var http = require('http'); + +var options = { + host: 'localhost', + port: 8081, + method: 'GET', +}; +var client_request = http.request(options); +client_request.on('response', function(response) { + console.log('HTTP status: ' + response.statusCode); + console.log('Headers:'); + console.log(response.headers); + + response.on('data', function(chunk) { + console.log(chunk.toString()); + }); +}); +client_request.end(); +``` ### Event: 'socket' +Event callback arguments: * `socket` {net.Socket} -This event is emitted when a socket is assigned to this request. `net.Socket` object is passed as argument to handler. +This event is emitted when a socket is assigned to this request. After response header is parsed, this event will be fired. +### request.abort() +Will abort the outgoing request, dropping any data to be sent/received and destroying the underlying socket. + ### request.end([data][, callback]) -* `data` {Buffer | string} -* `callback` {Function} +* `data` {Buffer | string} Data to be sent. +* `callback` {Function} Callback function invoked when all data is processed. Finishes sending the request. If `data` is provided, it sends `data` first, and finishes. If `callback` is specified, it is called when the request stream is finished. -### request.setTimeout(ms, cb) +This method must be called to close the request and to make sure all data is sent. + +**Example** + +```js +var http = require('http'); + +var message = 'HTTP Body POST Data'; +var options = { + host: 'localhost', + port: 8081, + method: 'POST', + headers: {'Content-Length': message.length}, +}; +var client_request = http.request(options, function(response) { + console.log('HTTP status: ' + response.statusCode); +}); +client_request.end(message); +``` + + +### request.setTimeout(ms[, callback]) * `ms` {number} -* `cb` {Function} +* `callback` {Function} The callback function registered for the `'timeout'` event. -Registers cb for 'timeout' event and set socket's timeout value to ms. This event will be triggered by the underlying socket's 'timeout' event. +Registers `callback` for 'timeout' event and set socket's timeout value to ms. This event will be triggered by the underlying socket's `'timeout'` event. -If cb is not provided, the socket will be destroyed automatically after timeout. -If you provides cb, you should handle the socket's timeout. +If `callback` is not provided, the socket will be destroyed automatically after timeout. +If `callback` is provied, the method should handle the socket's timeout. ### request.write(data[, callback]) -* `data` {Buffer | string} +* `data` {Buffer | string} Data to be sent. * `callback` {Function} Sends `data` as a request body. `callback` will be called when data is flushed. +**Example** + +```js +var http = require('http'); + +var message = "This is the data"; +var options = { + method: 'POST', + port: 8383, + path: '/', + headers: {'Content-Length': message.length}, +}; + +var client_request = http.request(options); +client_request.write(message); +client_request.end(); +``` + ## Class: http.IncomingMessage -http.IncomingMessage inherits `Stream.readable`. +This object is created internally and returned to the callback for the http.ClientRequest `'response'` event and +for the `'request'` event in the http.Server class. +In case of the `http.ClientRequest` class this `IncomingMessage` will represent the response sent by a server for the given request. +In case of the `http.Server` class this will represent the request sent by a client for the server. + +http.IncomingMessage inherits [`Stream.readable`](IoT.js-API-Stream.md). +See it's documentation to read incoming data from an HTTP request. +Notable events are `'data'` (fired when there is data to read), `'close'`, `'end'` (Request has ended) and the method `readable.read()`. + ### Event: 'close' When underlying connection is closed, 'close' event is emitted. +### Event: 'data' +Event callback arguments: +* `chunk` {Buffer} the buffer containing the data. + +Raised when there is data to be processed from the underlying socket. +It is highly possible that this chunk of data is not the whole data, +thus if the developer needs the whole data in one, each chunk must be +stored. (See the example for a naive approach.) + +The HTTP headers are already parsed before this event is triggered. + +Please note that the total size of the data could be bigger +than the memory available on the device where the code is running. + + +**Example** + +```js +var console = require('console'); +var http = require('http'); + +var options = { + host: 'localhost', + port: 8081, + method: 'GET', + path: '/' +}; +var client_request = http.request(options, function(response) { + var parts = []; + response.on('data', function(chunk) { + parts.push(chunk); + }); + response.on('end', function() { + var body = Buffer.concat(parts); + console.log(body.toString()); + }); +}); +client_request.end(); +``` + ### Event: 'end' This event is fired when no more data to be received. - +At this point it is safe to assume all data was received from the other end. ### message.headers -HTTP header object. +A JavaScript object containing all HTTP headers sent by the other end. ### message.method Requests method as `string` +### message.httpVersion +The HTTP version sent by the client. One of the following value: `'1.1'` or `'1.0'`. + ### message.socket -Underlying socket +Underlying network socket (`net.Socket`). ### message.statusCode HTTP response status code as `number` of 3-digit. -### message.statusMessage -HTTP response status message as `string` - ### message.url -Requests URL as `string` +Request URL as `string`. Only contains the URL present in the HTTP request. + +Note: only valid if the `IncomingMessage` was constructed by a `http.Server`. + +**Example** + +If the HTTP request is the following: + +``` +GET /page/1?data=a HTTP/1.1 \r\n +Accept: text/html\r\n +\r\n +``` + +the `message.url` will be: `/page/1?data=a`. + +### message.statusMessage +HTTP response status message as `string`. ### message.setTimeout(ms, cb) @@ -332,3 +544,147 @@ Requests URL as `string` * `cb` {Function} Registers cb for 'timeout' event set socket's timeout value to ms. This event will be triggered by the underlying socket's 'timeout' event. + + +## Class: http.ServerResponse + +Created internally when the `'request'` event is triggered by the `http.Server` class and +represents the response sent by the server to a client. + +### Event: 'close' +When underlying connection is closed, 'close' event is emitted. + +### Event: 'end' +This event is fired when no more data to be sent. + +### Event: 'finish' +This event is emitted when the response has been sent. It does not guarantee that client has received data yet. + + +### response.end([data][, callback]) +* `data` {Buffer | string} Data which should be sent. +* `callback` {Function} + +Finishes sending the response. + +If `data` is provided, it sends `data` first, and finishes. +If `callback` is specified, it is called when the response stream is finished. + +The method should be called to correctly finish up a response. +Any method which sets headers must be called before this method and before any `write` calls. + +**Example** + +```js +var console = require('console'); +var http = require('http'); + +var server = http.createServer(function(request, response) { + console.log('Request for path: ' + request.url); + + var message = '

Hello

'; + + response.setHeader('Content-Type', 'text/html'); + response.setHeader('Content-Length', message.length); + response.writeHead(200); + response.end(message); +}); + +var port = 8081 +server.listen(port, function() { + console.log('HTTP server listening on port: ' + port); +}); +``` + +### response.getHeader(name) +* `name` {string} Case-sensitive HTTP header field name. + +Returns the value of the `name` HTTP header field. + +### response.removeHeader(name) +* `name` {string} Case-sensitive HTTP header field name. + +Remove the HTTP header which has the `name` field name. +HTTP headers can not be modified after the first `write`, `writeHead` or `end` method call. + +### response.setHeader(name, value) +* `name` {string} The name of the HTTP header field to set. +* `value` {string} The value of the field. + +Sets response's header field(`name`) to `value`. If the field exists, it overwrites the existing value. +HTTP headers can not be modified after the first `write`, `writeHead` or `end` method call. + +### response.setTimeout(ms, cb) + +* `ms` {number} +* `cb` {Function} + +Registers cb for 'timeout' event and set socket's timeout value to ms. This event will be triggered by the underlying socket's 'timeout' event. + +### response.write(data[, callback]) +* `data` {Buffer | string} +* `callback` {Function} + +Sends `data` as a response body. `callback` will be called when data is flushed. + +It is advised to set at least the `Content-Length` HTTP header field correctly before +any `write` calls. This is so the client could properly handle the server response. + +After a `write` method was called there is no possibility to change any headers. + +**Example** + +```js +var console = require('console'); +var http = require('http'); + +var server = http.createServer(function(request, response) { + console.log('Request for path: ' + request.url); + + var message = '

Hello

'; + + response.setHeader('Content-Type', 'text/html'); + response.setHeader('Content-Length', message.length); + response.writeHead(200); + response.write(message); + response.end(); +}); + +var port = 8081 +server.listen(port, function() { + console.log('HTTP server listening on port: ' + port); +}); +``` + +### response.writeHead(statusCode[, statusMessage][, headers]) +* `statusCode` {number} +* `statusMessage` {string} Optional. If not set the HTTP status message will be inferred from the status code. +* `headers` {Object} Optional. An object containing HTTP header field names and values. + +Sets response status code, the status message and configures a set of HTTP +header values. + +**Example** + +```js +var console = require('console'); +var http = require('http'); + +var server = http.createServer(function(request, response) { + console.log('Request for path: ' + request.url); + + var message = '

Hello

'; + + response.writeHead(200, 'OK', { + 'Content-Type': 'text/html', + 'Content-Length': message.length, + }); + response.write(message); + response.end(); +}); + +var port = 8081 +server.listen(port, function() { + console.log('HTTP server listening on port: ' + port); +}); +``` diff --git a/docs/api/IoT.js-API-HTTPS.md b/docs/api/IoT.js-API-HTTPS.md new file mode 100644 index 0000000000..6a77795121 --- /dev/null +++ b/docs/api/IoT.js-API-HTTPS.md @@ -0,0 +1,104 @@ +### Platform Support + + The following shows Https module APIs available for each platform. + + | | Linux
(Ubuntu) | Tizen
(Raspberry Pi) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | TizenRT
(Artik053) | + | :---: | :---: | :---: | :---: | :---: | :---: | + | https.createServer | O | O | O | △ ¹ | △ ¹ | + | https.request | O | O | O | △ ¹ | △ ¹ | + | https.get | O | O | O | △ ¹ | △ ¹ | + +1. On NuttX/STM32F4-Discovery and TizenRT/Artik053, even a couple of sockets/server/requests might not work properly. + + +# Https + +IoT.js provides HTTPS to support HTTPS clients enabling users to send HTTPS requests easily. + +### https.createServer([options][, requestListener]) +* `options` {Object} Accepts the same `options` as [tls.createServer](IoT.js-API-TLS.md#tlscreateserveroptions-secureconnectionlistener) and [http.createServer](IoT.js-API-HTTP.md#httpcreateserverrequestlistener) methods. +* `requestListener` {Function} + * request {http.IncomingMessage} + * response {http.ServerResponse} +* Returns: {https.Server} + +To create a server the certificates should be specified via the `options` object. + +The `requestListener` is a function which is automatically added to the `'request'` event. + +**Example** + +```js +var options = { + key: fs.readFileSync('server.key'), + cert: fs.readFileSync('server.cert') +}; +var server = https.createServer(options, function(request, response) { + ... +}); +``` + + +### https.request(options[, callback]) +* `options` {Object} + * `host` {string} A domain name or IP address of the server to issue the request to. **Default:** 'localhost'. + * `hostname` {string} Alias for host. + * `port` {number} Port of remote server. **Default:** 443. + * `method` {string} A string specifying the HTTPS request method. **Default:** 'GET'. + * `path` {string} Request path. **Default:** '/'. Should include query string if any. E.G. '/index.html?page=12'. An exception is thrown when the request path contains illegal characters. Currently, only spaces are rejected but that may change in the future. + * `headers` {Object} An object containing request headers. + * `auth` {string} Optional Basic Authentication in the form `username:password`. Used to compute HTTPS Basic Authentication header. + * `ca` {string} Optional file path to CA certificate. Allows to override system trusted CA certificates. + * `cert` {string} Optional file path to client authentication certificate in PEM format. + * `key` {string} Optional file path to private keys for client cert in PEM format. + * `rejectUnauthorized` {boolean} Optional Specify whether to verify the Server's certificate against CA certificates. WARNING - Making this `false` may be a security risk. **Default:** `true` +* `callback` {Function} + * `response` {http.IncomingMessage} +* Returns: {http.ClientRequest} + +Example: +```javascript +var https = require('https'); + +var request = https.request({ + method: 'POST', + port: 443, + headers: {'Content-Length': 3} +}); + +... + +request.end(); +``` + +Note that in the example `req.end()` was called. With `https.request()` one must always call `req.end()` to signify that you're done with the request - even if there is no data being written to the request body. + +### https.get(options[, callback]) +* `options` {Object} + * `host` {string} A domain name or IP address of the server to issue the request to. **Default:** 'localhost'. + * `hostname` {string} Alias for host. + * `port` {number} Port of remote server. **Default:** 443. + * `method` {string} A string specifying the HTTPS request method. **Default:** 'GET'. + * `path` {string} Request path. **Default:** '/'. Should include query string if any. E.G. '/index.html?page=12'. An exception is thrown when the request path contains illegal characters. Currently, only spaces are rejected but that may change in the future. + * `headers` {Object} An object containing request headers. + * `auth` {string} Optional Basic Authentication in the form `username:password`. Used to compute HTTPS Basic Authentication header. + * `ca` {string} Optional file path to CA certificate. Allows to override system trusted CA certificates. + * `cert` {string} Optional file path to client authentication certificate in PEM format. + * `key` {string} Optional file path to private keys for client cert in PEM format. + * `rejectUnauthorized` {boolean} Optional Specify whether to verify the Server's certificate against CA certificates. WARNING - Making this `false` may be a security risk. **Default:** `true` +* `callback` {Function} + * `response` {http.IncomingMessage} +* Returns: {http.ClientRequest} + +Same as `https.request` except that `https.get` automatically call `req.end()` at the end. + +Example: +```javascript +var https = require('https'); + +https.get({ + port: 443, +}, function(res) { +... +}); +``` diff --git a/docs/api/IoT.js-API-I2C.md b/docs/api/IoT.js-API-I2C.md index e62270a014..fe0f0f9669 100644 --- a/docs/api/IoT.js-API-I2C.md +++ b/docs/api/IoT.js-API-I2C.md @@ -2,53 +2,63 @@ The following shows I2C module APIs available for each platform. -| | Linux
(Ubuntu) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | -| :---: | :---: | :---: | :---: | -| i2c.open | O | O | O | -| i2cbus.read | O | O | O | -| i2cbus.write | O | O | O | -| i2cbus.close | O | O | O | +| | Linux
(Ubuntu) | Tizen
(Raspberry Pi) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | TizenRT
(Artik053) | +| :---: | :---: | :---: | :---: | :---: | :---: | +| i2c.open | X | O | O | O | O | +| i2c.openSync | X | O | O | O | O | +| i2cbus.read | X | O | O | O | O | +| i2cbus.readSync | X | O | O | O | O | +| i2cbus.write | X | O | O | O | O | +| i2cbus.writeSync | X | O | O | O | O | +| i2cbus.close | X | O | O | O | O | +| i2cbus.closeSync | X | O | O | O | O | # I2C -The I2C class supports the I2C protocol. I2C bus has two signals - SDA and SCL. +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). -### new I2C() +### i2c.open(configuration, callback) +* `configuration` {Object} Configuration for open I2CBus. + * `device` {string} Device path. (only on Linux) + * `bus` {number} The specified bus number. (Tizen, TizenRT and NuttX only) + * `address` {number} Device address. +* `callback` {Function} + * `err` {Error|null} + * `i2cBus` {Object} An instance of I2CBus. +* Returns: {Object} An instance of I2CBus. -Returns with an I2C object. +Get I2CBus object with configuration asynchronously. **Example** ```js -var I2C = require('i2c'); +var i2c = require('i2c'); -var i2c = new I2C(); +i2c.open({device: '/dev/i2c-1', address: 0x23}, function(err, wire) { + if (err) { + throw err; + } +}); ``` - -### i2c.open(configuration[, callback]) +### i2c.openSync(configuration) * `configuration` {Object} Configuration for open I2CBus. - * `device` {string(linux)|number(NuttX)} Device path. + * `device` {string} Device path. (only on Linux) + * `bus` {number} The specified bus number. (Tizen, TizenRT and NuttX only) * `address` {number} Device address. -* `callback` {Function} - * `err` {Error|null} * Returns: {Object} An instance of I2CBus. -Get I2CBus object with configuration. +Get I2CBus object with configuration synchronously. **Example** ```js -var I2C = require('i2c'); +var i2c = require('i2c'); -var i2c = new I2C(); -var i2c_bus = i2c.open({device: '/dev/i2c-1', address: 0x23}, function(err) { - if (err) { - throw err; - } -}); +var wire = i2c.openSync({device: '/dev/i2c-1', address: 0x23}); ``` @@ -61,21 +71,36 @@ var i2c_bus = i2c.open({device: '/dev/i2c-1', address: 0x23}, function(err) { * `err` {Error|null} * `res` {Array} Array of bytes. -Read bytes from I2C device. +Read bytes from I2C device asynchronously. **Example** ```js -var I2C = require('i2c'); +var i2c = require('i2c'); + +i2c.open({device: '/dev/i2c-1', address: 0x23}, function(err, wire) { + wire.read(2, function(err, res) { + if (!err) { + console.log('read result: ' + res); + } + }); +}); +``` -var i2c = new I2C(); -var i2c_bus = i2c.open({device: '/dev/i2c-1', address: 0x23}); +### i2cbus.readSync(length) +* `length` {number} Number of bytes to read. +* Returns: {Array} Array of bytes. -i2c_bus.read(2, function(err, res) { - if (!err) { - console.log('read result: ' + res); - } -}); +Read bytes from I2C device synchronously. + +**Example** + +```js +var i2c = require('i2c'); + +var wire = i2c.openSync({device: '/dev/i2c-1', address: 0x23}); +var res = wire.readSync(2); +console.log(res); ``` ### i2cbus.write(bytes[, callback]) @@ -83,35 +108,61 @@ i2c_bus.read(2, function(err, res) { * `callback` {Function} * `err` {Error|null} -Write bytes to I2C device. +Write bytes to I2C device asynchronously. **Example** ```js -var I2C = require('i2c'); - -var i2c = new I2C(); -var i2c_bus = i2c.open({device: '/dev/i2c-1', address: 0x23}); - -i2c_bus.write([0x10], function(err) { - if(!err) { - console.log('write done'); - } +var i2c = require('i2c'); + +i2c.open({device: '/dev/i2c-1', address: 0x23}, function(err, wire){ + wire.write([0x10], function(err) { + if(!err) { + console.log('write done'); + } + }); }); ``` +### i2cbus.writeSync(bytes) +* `bytes` {Array} Array of bytes to write. -### i2cbus.close() - -Close I2C device. +Write bytes to I2C device synchronously. **Example** ```js -var I2C = require('i2c'); +var i2c = require('i2c'); + +var wire = i2c.openSync({device: '/dev/i2c-1', address: 0x23}); +wire.writeSync([0x10]); +``` + +### i2cbus.close([callback]) +* `callback` {Function} + * `err` {Error|null} -var i2c = new I2C(); -var i2c_bus = i2c.open({device: '/dev/i2c-1', address: 0x23}); +Close I2C device asynchronously. -i2c_bus.close(); +**Example** + +```js +var i2c = require('i2c'); + +i2c.open({device: '/dev/i2c-1', address: 0x23}, function(err, wire) { + wire.close(); +}); ``` + +### i2cbus.closeSync() + +Close I2C device synchronously. + +**Example** + +```js +var i2c = require('i2c'); + +var wire = i2c.openSync({device: '/dev/i2c-1', address: 0x23}); +wire.closeSync(); +``` \ No newline at end of file diff --git a/docs/api/IoT.js-API-MQTT.md b/docs/api/IoT.js-API-MQTT.md new file mode 100644 index 0000000000..7558b2e103 --- /dev/null +++ b/docs/api/IoT.js-API-MQTT.md @@ -0,0 +1,163 @@ +### Platform Support + +The following chart shows the availability of each MQTT module API function on each platform. + +| | Linux
(Ubuntu) | Tizen
(Raspberry Pi) | Raspbian
(Raspberry Pi) | Nuttx
(STM32F4-Discovery) | TizenRT
(Artik053) | +| :---: | :---: | :---: | :---: | :---: | :---: | +| mqtt.connect | O | O | O | X | O | +| mqtt.end | O | O | O | X | O | +| mqtt.publish | O | O | O | X | O | +| mqtt.subscribe | O | O | O | X | O | +| mqtt.unsubscribe | O | O | O | X | O | + +# 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 separating 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.connect([url], [options], [callback]) +- `url` {string} host name optionally prefixed by `mqtt://` or `mqtts://`. +- `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. + - `socket` {net.Socket | TLSSocket} If a `TLSSocket` is given for secure communication it is the user's responsibility to connect it to establish the TLS connection first. Otherwise the client automatically connects the socket to the server. + - `username` {Buffer | string} Optional. Use username when connecting 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. +- `callback` {function} the function which will be executed when the client successfully connected to the broker. + +Returns with an MQTTClient object and starts connecting to a broker. Emits a `connect` event after the connection is completed. + + +**Example** +```js +var mqtt = require('mqtt'); + +var opts = { + port: 443, + keepalive: 10, + clientId: 'IoT.js Client', +} + +var client = mqtt.connect('mqtt://127.0.0.1', opts, function () { + client.end(); +}); +``` + +### mqtt.end([force]) +- `force` {boolean} force network connection abort + +Disconnects the client from the broker. + +### mqtt.subscribe(topic, [options], [callback]) +- `topic` {Buffer | string} topic to subscribe to +- `options` {Object} + - `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`. +- `callback` {function} the function which will be executed when the subscribe is completed. + + +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 = { + retain: false, + qos: 2 +} + +var client = mqtt.connect(opts, function () { + client.subscribe('hello/#/iotjs', subscribe_opts, function(error) { + if (error) { + console.log('Subscribe is failed'); + } else { + console.log('Subscribe is successfully completed'); + } + }); +}); + +client.on('message', function(data) { + console.log('I received something: ' + data.message.toString()); +}); +``` + +### mqtt.unsubscribe(topic, [callback]) +- `topic` {Buffer | string} topic to unsubscribe from +- `callback` {function} the function which will be executed when the unsubscribe is completed. + +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(topic, message, [options], [callback]) +- `topic` {Buffer | string} topic to publish to +- `message` {Buffer | string} message to send +- `options` {Object} + - `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. +- `callback` {function} the function which will be executed when the publish is completed + + +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 client = mqtt.connect(opts, function () { + client.publish('hello/#/iotjs', 'Hello MQTT clients!', { qos:1 }, function() { + console.log('Message has been published'); + }); +}); +``` + +## 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 occurred 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. diff --git a/docs/api/IoT.js-API-Module.md b/docs/api/IoT.js-API-Module.md index ab1d963620..27fb9ad39e 100644 --- a/docs/api/IoT.js-API-Module.md +++ b/docs/api/IoT.js-API-Module.md @@ -2,9 +2,9 @@ The following shows module APIs available for each platform. -| | Linux
(Ubuntu) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | -| :---: | :---: | :---: | :---: | -| require | O | O | O | +| | Linux
(Ubuntu) | Tizen
(Raspberry Pi) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | TizenRT
(Artik053) | +| :---: | :---: | :---: | :---: | :---: | :---: | +| require | O | O | O | O | O | # Module The `require` function is always available there is no need to import `module` explicitly. @@ -33,6 +33,7 @@ If a native module named `id` exists, load it and return. 2. `iotjs_modules` folder under current working directory. 3. `$HOME/iotjs_modules` 4. `$IOTJS_PATH/iotjs_modules` +5. `$IOTJS_EXTRA_MODULE_PATH` For each directory in search paths above: @@ -41,3 +42,15 @@ For each directory in search paths above: - If a directory `id` exists, module system consider the directory as a package: - If `id/package.json` contains **main** property, load the file named **main** property. - If `id/package.json` exists, but neither the **main** property nor the file named **main** property exist, load `index.js`. +- Extra step for Linux/Tizen targets: + - If a file with `id.node` exists, try to load it as an N-API native addon 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. + +`IOTJS_EXTRA_MODULE_PATH=./node_modules:./my_modules` diff --git a/docs/api/IoT.js-API-N-API.md b/docs/api/IoT.js-API-N-API.md new file mode 100644 index 0000000000..d0f32c0b1a --- /dev/null +++ b/docs/api/IoT.js-API-N-API.md @@ -0,0 +1,262 @@ +### Platform Support + +The following chart shows the availability of each N-API function on each platform. +The functions point to the related part of the official N-API documentation. + +| Supported features | Linux
(Ubuntu) | +| :---: | :---: | +| [napi_add_env_cleanup_hook](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_add_env_cleanup_hook) | O | +| [napi_async_complete_callback](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_async_complete_callback) | O | +| [napi_async_destroy](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_async_destroy) | O | +| [napi_async_execute_callback](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_async_execute_callback) | O | +| [napi_async_init](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_async_init) | O | +| [napi_callback](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_callback_info) | O | +| [napi_callback_info](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_callback_info) | O | +| [napi_call_function](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_call_function) | O | +| [napi_cancel_async_work](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_cancel_async_work) | O | +| [napi_close_callback_scope](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_close_callback_scope) | O | +| [napi_close_escapable_handle_scope](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_close_escapable_handle_scope) | O | +| [napi_close_handle_scope](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_close_handle_scope) | O | +| [napi_coerce_to_bool](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_coerce_to_bool) | O | +| [napi_coerce_to_number](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_coerce_to_number) | O | +| [napi_coerce_to_object](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_coerce_to_object) | O | +| [napi_coerce_to_string](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_coerce_to_string) | O | +| [napi_create_array](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_array) | O | +| [napi_create_arraybuffer](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_arraybuffer) | O | +| [napi_create_array_with_length](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_array_with_length) | O | +| [napi_create_async_work](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_async_work) | O | +| [napi_create_buffer](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_buffer) | O | +| [napi_create_buffer_copy](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_buffer_copy) | O | +| [napi_create_dataview](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_dataview) | O | +| [napi_create_double](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_double) | O | +| [napi_create_error](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_error) | O | +| [napi_create_external](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_external) | O | +| [napi_create_external_arraybuffer](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_external_arraybuffer) | O | +| [napi_create_external_buffer](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_external_buffer) | O | +| [napi_create_function](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_function) | O | +| [napi_create_int32](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_int32) | O | +| [napi_create_int64](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_int64) | O | +| [napi_create_object](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_object) | O | +| [napi_create_promise](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_promise) | O | +| [napi_create_range_error](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_range_error) | O | +| [napi_create_reference](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_reference) | O | +| [napi_create_string_latin1](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_string_latin1) | O | +| [napi_create_string_utf16](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_string_utf16) | O | +| [napi_create_string_utf8](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_string_utf8) | O | +| [napi_create_symbol](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_symbol) | O | +| [napi_create_threadsafe_function](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_threadsafe_function) | O | +| [napi_create_typedarray](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_typedarray) | O | +| [napi_create_type_error](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_type_error) | O | +| [napi_create_uint32](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_uint32) | O | +| [napi_define_class](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_define_class) | O | +| [napi_define_properties](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_define_properties) | O | +| [napi_delete_async_work](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_delete_async_work) | O | +| [napi_delete_element](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_delete_element) | O | +| [napi_delete_property](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_delete_property) | O | +| [napi_delete_reference](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_delete_reference) | O | +| [napi_env](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_env) | O | +| [napi_escapable_handle_scope](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_escapable_handle_scope) | O | +| [napi_escape_handle](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_escape_handle) | O | +| [napi_extended_error_info](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_extended_error_info) | O | +| [napi_fatal_error](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_fatal_error) | O | +| [napi_fatal_exception](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_fatal_exception) | O | +| [napi_finalize](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_finalize) | O | +| [napi_get_and_clear_last_exception](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_and_clear_last_exception) | O | +| [napi_get_arraybuffer_info](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_arraybuffer_info) | O | +| [napi_get_array_length](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_array_length) | O | +| [napi_get_boolean](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_boolean) | O | +| [napi_get_buffer_info](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_buffer_info) | O | +| [napi_get_cb_info](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_cb_info) | O | +| [napi_get_dataview_info](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_dataview_info) | O | +| [napi_get_element](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_element) | O | +| [napi_get_global](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_global) | O | +| [napi_get_last_error_info](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_last_error_info) | O | +| [napi_get_named_property](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_named_property) | O | +| [napi_get_new_target](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_new_target) | O | +| [napi_get_node_version](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_node_version) | O | +| [napi_get_null](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_null) | O | +| [napi_get_property](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_property_names) | O | +| [napi_get_property_names](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_property_names) | O | +| [napi_get_prototype](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_prototype) | O | +| [napi_get_reference_value](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_reference_value) | O | +| [napi_get_typedarray_info](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_typedarray_info) | O | +| [napi_get_undefined](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_undefined) | O | +| [napi_get_uv_event_loop](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_uv_event_loop) | O | +| [napi_get_value_bool](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_value_bool) | O | +| [napi_get_value_double](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_value_double) | O | +| [napi_get_value_external](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_value_external) | O | +| [napi_get_value_int32](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_value_int32) | O | +| [napi_get_value_int64](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_value_int64) | O | +| [napi_get_value_string_latin1](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_value_string_latin1) | O | +| [napi_get_value_string_utf16](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_value_string_utf16) | O | +| [napi_get_value_string_utf8](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_value_string_utf8) | O | +| [napi_get_value_uint32](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_value_uint32) | O | +| [napi_get_version](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_version) | O | +| [napi_handle_scope](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_handle_scope) | O | +| [napi_has_element](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_has_element) | O | +| [napi_has_named_property](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_has_named_property) | O | +| [napi_has_own_property](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_has_own_property) | O | +| [napi_has_property](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_has_property) | O | +| [napi_instanceof](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_instanceof) | O | +| [napi_is_array](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_is_array) | O | +| [napi_is_arraybuffer](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_is_arraybuffer) | O | +| [napi_is_buffer](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_is_buffer) | O | +| [napi_is_dataview](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_is_dataview) | O | +| [napi_is_error](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_is_error) | O | +| [napi_is_exception_pending](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_is_exception_pending) | O | +| [napi_is_promise](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_is_promise) | O | +| [napi_is_typedarray](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_is_typedarray) | O | +| [napi_make_callback](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_make_callback) | O | +| [napi_new_instance](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_new_instance) | O | +| [napi_open_callback_scope](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_open_callback_scope) | O | +| [napi_open_escapable_handle_scope](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_open_escapable_handle_scope) | O | +| [napi_open_handle_scope](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_open_handle_scope) | O | +| [napi_property_attributes](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_property_attributes) | O | +| [napi_property_descriptor](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_property_descriptor) | O | +| [napi_queue_async_work](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_queue_async_work) | O | +| [napi_ref](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_ref) | O | +| [napi_reference_ref](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_reference_ref) | O | +| [napi_reference_unref](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_reference_unref) | O | +| [napi_reject_deferred](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_reject_deferred) | O | +| [napi_remove_env_cleanup_hook](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_remove_env_cleanup_hook) | O | +| [napi_remove_wrap](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_remove_wrap) | O | +| [napi_resolve_deferred](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_resolve_deferred) | O | +| [napi_set_element](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_set_element) | O | +| [napi_set_named_property](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_set_named_property) | O | +| [napi_set_property](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_set_property) | O | +| [napi_status](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_status) | O | +| [napi_strict_equals](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_strict_equals) | O | +| [napi_throw](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_throw) | O | +| [napi_throw_error](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_throw_error) | O | +| [napi_throw_range_error](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_throw_range_error) | O | +| [napi_throw_type_error](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_throw_type_error) | O | +| [napi_typedarray_type](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_typedarray_type) | O | +| [napi_typeof](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_typeof) | O | +| [napi_unwrap](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_unwrap) | O | +| [napi_value](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_value) | O | +| [napi_valuetype](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_valuetype) | O | +| [napi_wrap](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_wrap) | O | + +### The API does not support the following features: + - [napi_threadsafe_function](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_threadsafe_function) + - [napi_threadsafe_function_release_mode](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_threadsafe_function_release_mode) + - [napi_threadsafe_function_call_mode](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_threadsafe_function_call_mode) + - [napi_threadsafe_function_call_js](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_threadsafe_function_call_js) + - [napi_create_bigint_int64](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_bigint_int64) + - [napi_create_bigint_uint64](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_bigint_uint64) + - [napi_create_bigint_words](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_bigint_words) + - [napi_get_value_bigint_int64](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_value_bigint_int64) + - [napi_get_value_bigint_uint64](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_value_bigint_uint64) + - [napi_get_value_bigint_words](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_value_bigint_words) + - [napi_add_finalizer](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_add_finalizer) + - [Asynchronous Thread-safe Function Calls:](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_asynchronous_thread_safe_function_calls) + - [napi_create_threadsafe_function](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_create_threadsafe_function) + - [napi_get_threadsafe_function_context](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_get_threadsafe_function_context) + - [napi_call_threadsafe_function](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_call_threadsafe_function) + - [napi_acquire_threadsafe_function](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_acquire_threadsafe_function) + - [napi_release_threadsafe_function](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_release_threadsafe_function) + - [napi_ref_threadsafe_function](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_ref_threadsafe_function) + - [napi_unref_threadsafe_function](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_napi_unref_threadsafe_function) + + +# N-API + +Based on Node.js v10.15 (LTS) + +N-API (pronounced N as in the letter, followed by API) is an API for building native Addons. N-API is generally used to create and manipulate JavaScript values. You can read more about N-API [here](https://nodejs.org/dist/latest-v10.x/docs/api/n-api.html#n_api_n_api). + +Our implementation works with either ES2015 enabled or disabled. All of the N-API ES2015 features throw an exception when IoT.js isn't compiled with ES2015 yet they are used. + +### Building N-API with IoT.js + +You need to append the `--n-api` parameter to the build command (e.g. `tools/build.py --n-api`). +This automatically adds the N-API module to IoT.js. + +To run N-API test you should also append `--n-api` after the `testrunner.py`. + +### Building a simple module + +### node-gyp + +C++ code needs to be compiled into executable form whether it be as an object +file to linked with others, a shared library, or a standalone executable. + +The main reason for this is that we need to link to the Node.js dependencies and +headers correctly, another reason is that we need a cross platform way to build +C++ source into binary for the target platform. + +Until now **node-gyp** is the **de-facto** standard build tool for writing +Node.js addons. It's based on Google's **gyp** build tool, which abstract away +many of the tedious issues related to cross platform building. + +**node-gyp** uses a file called ```binding.gyp``` that is located on the root of +your addon project. + +```binding.gyp``` file, contains all building configurations organized with a +JSON like syntax. The most important parameter is the **target** that must be +set to the same value used on the initialization code of the addon as in the +examples reported below: + +#### **binding.gyp** + +```gyp +{ + "targets": [ + { + # myModule is the name of your native addon + "target_name": "myModule", + "sources": ["src/my_module.cc", ...], + ... + ] +} +``` + +#### **my_module.cc** + +```cpp +#include + +// ... + +/** +* This code is our entry-point. We receive two arguments here, the first is the +* environment that represent an independent instance of the JavaScript runtime, +* the second is exports, the same as module.exports in a .js file. +* You can either add properties to the exports object passed in or create your +* own exports object. In either case you must return the object to be used as +* the exports for the module when you return from the Init function. +*/ +Napi::Object Init(Napi::Env env, Napi::Object exports) { + + // ... + + return exports; +} + +/** +* This code defines the entry-point for the Node addon, it tells Node where to go +* once the library has been loaded into active memory. The first argument must +* match the "target" in our *binding.gyp*. Using NODE_GYP_MODULE_NAME ensures +* that the argument will be correct, as long as the module is built with +* node-gyp (which is the usual way of building modules). The second argument +* points to the function to invoke. The function must not be namespaced. +*/ +NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init) +``` + +#### **node-gyp** reference + + - [Installation](https://www.npmjs.com/package/node-gyp#installation) + - [How to use](https://www.npmjs.com/package/node-gyp#how-to-use) + - [The binding.gyp file](https://www.npmjs.com/package/node-gyp#the-bindinggyp-file) + - [Commands](https://www.npmjs.com/package/node-gyp#commands) + - [Command options](https://www.npmjs.com/package/node-gyp#command-options) + - [Configuration](https://www.npmjs.com/package/node-gyp#configuration) + +Sometimes finding the right settings for ```binding.gyp``` is not easy so to +accomplish at most complicated task please refer to: + +- [GYP documentation](https://gyp.gsrc.io/index.md) +- [node-gyp wiki](https://github.com/nodejs/node-gyp/wiki) +The most important parameter is the target that must be set to the same value used on the initialization code of the addon. +To use the N-API functions you need to include `node-api.h` in your native module. \ No newline at end of file diff --git a/docs/api/IoT.js-API-Net.md b/docs/api/IoT.js-API-Net.md index 770dcf2661..08124ebcc8 100644 --- a/docs/api/IoT.js-API-Net.md +++ b/docs/api/IoT.js-API-Net.md @@ -2,28 +2,28 @@ The following shows net module APIs available for each platform. -| | Linux
(Ubuntu) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | -| :---: | :---: | :---: | :---: | -| net.createServer | O | O | △ ¹ | -| net.connect | O | O | △ ¹ | -| net.createConnection | O | O | △ ¹ | -| net.Server.listen | O | O | △ ¹ | -| net.Server.close | O | O | △ ²| -| net.Socket.connect | O | O | △ ¹ | -| net.Socket.write | O | O | △ ¹ | -| net.Socket.end | O | O | △ ¹ ³ | -| net.Socket.destroy | O | O | △ ¹ ³ | -| net.Socket.pause | O | O | △ ¹ | -| net.Socket.resume | O | O | △ ¹ | -| net.Socket.setTimeout | O | O | △ ¹ | -| net.Socket.setKeepAlive | X | X | X | - -1. On NuttX/STM32F4-Discovery, even a couple of sockets/server/requests might not work properly. +| | Linux
(Ubuntu) | Tizen
(Raspberry Pi) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | TizenRT
(Artik053) | +| :---: | :---: | :---: | :---: | :---: | :---: | +| net.createServer | O | O | O | △ ¹ | △ ¹ | +| net.connect | O | O | O | △ ¹ | △ ¹ | +| net.createConnection | O | O | O | △ ¹ | △ ¹ | +| net.Server.listen | O | O | O | △ ¹ | △ ¹ | +| net.Server.close | O | O | O | △ ²| O | +| net.Socket.connect | O | O | O | △ ¹ | △ ¹ | +| net.Socket.write | O | O | O | △ ¹ | △ ¹ | +| net.Socket.end | O | O | O | △ ¹ ³ | △ ¹ ³ | +| net.Socket.destroy | O | O | O | △ ¹ ³ | △ ¹ ³ | +| net.Socket.pause | O | O | O | △ ¹ | △ ¹ | +| net.Socket.resume | O | O | O | △ ¹ | △ ¹ | +| net.Socket.setTimeout | O | O | O | △ ¹ | △ ¹ | +| net.Socket.setKeepAlive | X | X | X | X | X | + +1. On NuttX/STM32F4-Discovery and TizenRT/Artik053, even a couple of sockets/server/requests might not work properly. 2. On NuttX/STM32F4-Discovery, close() may block due to a bug in poll(). 3. When writable stream is finished but readable stream is still alive, IoT.js tries to shutdown the socket, not destroy. -However on `NuttX` due to lack of implementation, it does nothing inside. +However on `NuttX` and `TizenRT` due to lack of implementation, it does nothing inside. # Net diff --git a/docs/api/IoT.js-API-PWM.md b/docs/api/IoT.js-API-PWM.md index d7695939e0..501a645ad3 100644 --- a/docs/api/IoT.js-API-PWM.md +++ b/docs/api/IoT.js-API-PWM.md @@ -2,53 +2,47 @@ The following shows PWM module APIs available for each platform. -| | Linux
(Ubuntu) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | -| :---: | :---: | :---: | :---: | -| pwm.open | O | O | O | -| pwmpin.setPeriod | O | O | O | -| pwmpin.setPeriodSync | O | O | O | -| pwmpin.setFrequency | O | O | O | -| pwmpin.setFrequencySync | O | O | O | -| pwmpin.setDutyCycle | O | O | O | -| pwmpin.setDutyCycleSync | O | O | O | -| pwmpin.setEnable | O | O | O | -| pwmpin.setEnableSync | O | O | O | -| pwmpin.close | O | O | O | -| pwmpin.closeSync | O | O | O | +| | Linux
(Ubuntu) | Tizen
(ARTIK530) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | TizenRT
(ARTIK053) | +| :---: | :---: | :---: | :---: | :---: | :---: | +| pwm.open | X | O | O | O | O | +| pwm.openSync | X | O | O | O | O | +| pwmpin.setPeriod | X | O | O | O | O | +| pwmpin.setPeriodSync | X | O | O | O | O | +| pwmpin.setFrequency | X | O | O | O | O | +| pwmpin.setFrequencySync | X | O | O | O | O | +| pwmpin.setDutyCycle | X | O | O | O | O | +| pwmpin.setDutyCycleSync | X | O | O | O | O | +| pwmpin.setEnable | X | O | O | O | O | +| pwmpin.setEnableSync | X | O | O | O | O | +| pwmpin.close | X | O | O | O | O | +| pwmpin.closeSync | X | O | O | O | O | ## Class: PWM -### new PWM() - -Returns a new PWM object which can open a PWM pin. - -This object allows the developer to specify a pin and generate a pulse-width modulatated (PWM) -signal through that. - -### pwm.open(configuration[, callback]) +### pwm.open(configuration, callback) * `configuration` {Object} Configuration object which can have the following properties. * `pin` {number} The pin number to use with this PWM object (mandatory configuration). * `chip` {number} The PWM chip number (only on Linux). **Default:** `0`. * `period` {number} The period of the PWM signal, in seconds (positive number). - * `frequency` {integer} In Hz (positive integer). * `dutyCycle` {number} The active time of the PWM signal, must be within the `0.0` and `1.0` range. * `callback` {Function} Callback function. * `err` {Error|null} The error object or `null` if there were no error. -* Returns: `` + * `pwmpin` {Object} An instance of PWMPin. +* Returns: {Object} An instance of PWMPin. Opens PWM pin with the specified configuration. To correctly open a PWM pin one must know the correct pin number: * On Linux, `pin` is a number which is `0` or `1`. +* On Tizen, `pin` is a number which is `2`. (Only ARTIK530 board support PWM.) * On NuttX, you have to know pin name. The pin name is defined in target board module. For more module information, please see below list. * [STM32F4-discovery](../targets/nuttx/stm32f4dis/IoT.js-API-Stm32f4dis.md#pwm-pin) **Example** ```js -var Pwm = require('pwm'); -var pwm = new Pwm(); +var pwm = require('pwm'); var config = { pin: 0, period: 0.1, @@ -61,6 +55,33 @@ var pwm0 = pwm.open(config, function(err) { }); ``` +### pwm.openSync(configuration) +* `configuration` {Object} Configuration object which can have the following properties. + * `pin` {number} The pin number to use with this PWM object (mandatory configuration). + * `chip` {number} The PWM chip number (only on Linux). **Default:** `0`. + * `period` {number} The period of the PWM signal, in seconds (positive number). + * `dutyCycle` {number} The active time of the PWM signal, must be within the `0.0` and `1.0` range. +* Returns: {Object} An instance of PWMPin. + +Opens PWM pin with the specified configuration. + +To correctly open a PWM pin one must know the correct pin number: +* On Linux, `pin` is a number which is `0` or `1`. +* On NuttX, you have to know pin name. The pin name is defined in target board module. For more module information, please see below list. + * [STM32F4-discovery](../targets/nuttx/stm32f4dis/IoT.js-API-Stm32f4dis.md#pwm-pin) + + +**Example** +```js +var pwm = require('pwm'); +var config = { + pin: 0, + period: 0.1, + dutyCycle: 0.5 +} +var pwm0 = pwm.openSync(config); +``` + ## Class: PWMPin @@ -110,7 +131,7 @@ console.log('done'); * `callback` {Function} * `err` {Error|null} The error object or `null` if there were no error. -The `setFequency` method congifures the frequency of the PWM signal. +The `setFrequency` method configures the frequency of the PWM signal. `frequency` is the measurement of how often the signal is repeated in a single period. Configuration is done asynchronously and the `callback` method is invoked after the @@ -133,7 +154,7 @@ console.log('do'); ### pwmpin.setFrequencySync(frequency) * `frequency` {integer} In Hz (positive integer). -The `setFequencySync` method congifures the frequency of the PWM signal. +The `setFrequencySync` method configures the frequency of the PWM signal. `frequency` is the measurement of how often the signal is repeated in a single period. Configuration is done synchronously and will block till the frequency is configured. diff --git a/docs/api/IoT.js-API-Process.md b/docs/api/IoT.js-API-Process.md index ad556cdc3c..6452ddb02d 100644 --- a/docs/api/IoT.js-API-Process.md +++ b/docs/api/IoT.js-API-Process.md @@ -2,12 +2,12 @@ The following shows process module APIs available for each platform. -| | Linux
(Ubuntu) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | -| :---: | :---: | :---: | :---: | -| process.nextTick | O | O | O | -| process.exit | O | O | O | -| process.cwd | O | O | O | -| process.chdir | O | O | O | +| | Linux
(Ubuntu) | Tizen
(Raspberry Pi) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | TizenRT
(Artik053) | +| :---: | :---: | :---: | :---: | :---: | :---: | +| process.nextTick | O | O | O | O | O | +| process.exit | O | O | O | O | O | +| process.cwd | O | O | O | O | O | +| process.chdir | O | O | O | O | O | ※ On NuttX, you should pass absolute path to `process.chdir`. @@ -47,6 +47,8 @@ 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. **Example** @@ -69,13 +71,14 @@ Specifying an exit code for the `process.exit()` call will override any previous The `iotjs` property holds IoT.js related information in an object. The following keys can be accessed via this property: -* `board` specifies the device type on which the IoT.js is running currently. For instance `'STM32F4DIS'`, `'RP2'`, or `'unknown'`. +* `board` specifies the device type on which the IoT.js is running currently. +For instance `'artik05x'`, `'artik10'`, `'rpi2'`,`'stm32f4dis'`, or `'unknown'`. **Example** ```js console.log(process.iotjs.board); -// on Raspberry 2 it prints: RP2 +// on Raspberry 2 it prints: rpi2 ``` ### process.platform @@ -123,7 +126,7 @@ IoT.js will not exit till all `'exit'` event listeners are called. The `process.exit()` method call will force the process to exit as quickly as possible, ignoring if there is any asynchronous operations still pending. -In most situations, it is not necessary to explcitly call `process.exit()`. The IoT.js will exit on its own +In most situations, it is not necessary to explicitly call `process.exit()`. The IoT.js will exit on its own if there is no additional work pending in the event loop. The `process.exitCode` property can be set to exit code when the process exits gracefully. @@ -146,8 +149,9 @@ doSomeWork() process.exitCode = 1; ``` -### process.nextTick(callback) +### process.nextTick(callback, [...args]) * `callback` {Function} +* `...args` {any} Additional arguments to pass when invoking the callback The `nextTick` method adds the `callback` method to the "next tick queue". Once the current turn of the event loop is completed, all callbacks currently in the next tick queue will be called. @@ -167,6 +171,18 @@ console.log('step 3'); // step 2 ``` +### process.version +* {string} + +The `version` property returns the version numbering of the currently running IoT.js process as a string. + +**Example** +```js +console.log(process.version); +// prints: (in case of version 1.0.0) +// 1.0.0 +``` + ### Event: 'exit' * `callback` {Function} * `code` {integer} exitCode diff --git a/docs/api/IoT.js-API-SPI.md b/docs/api/IoT.js-API-SPI.md index 8677088187..0fc3b9b078 100644 --- a/docs/api/IoT.js-API-SPI.md +++ b/docs/api/IoT.js-API-SPI.md @@ -2,22 +2,23 @@ The following shows spi module APIs available for each platform. -| | Linux
(Ubuntu) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | -| :---: | :---: | :---: | :---: | -| spi.open | O | O | X | -| spibus.transfer | O | O | X | -| spibus.transferSync | O | O | X | -| spibus.close | O | O | X | -| spibus.closeSync | O | O | X | +| | Linux
(Ubuntu) | Tizen
(Raspberry Pi) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | TizenRT
(Artik053) | +| :---: | :---: | :---: | :---: | :---: | :---: | +| spi.open | X | O | O | O | O | +| spi.openSync | X | O | O | O | O | +| spibus.transfer | X | O | O | O | O | +| spibus.transferSync | X | O | O | O | O | +| spibus.close | X | O | O | O | O | +| spibus.closeSync | X | O | O | O | O | ## Class: SPI SPI (Serial Peripheral Interface) is a communication protocol which defines a way to communicate between devices. -### new SPI() - -Returns a new SPI object which can open SPI bus. +* 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 The clock polarity and the clock phase can be specified as `0` or `1` to form four unique modes to provide flexibility in communication between devices. The `SPI.MODE` will specify which one to use (the combinations of the polarity and phase). @@ -27,7 +28,6 @@ The clock polarity and the clock phase can be specified as `0` or `1` to form fo * `2` Clock Polarity(1), Clock Phase(0), Clock Edge(1) * `3` Clock Polarity(1), Clock Phase(1), Clock Edge(0) - ### SPI.CHIPSELECT * `NONE` * `HIGH` @@ -40,9 +40,10 @@ The chip select is an access-enable switch. When the chip select pin is in the ` Sets the order of the bits shifted out of and into the SPI bus, either MSB (most-significant bit first) or LSB (least-significant bit first). -### spi.open(configuration[, callback]) +### spi.open(configuration, callback) * `configuration` {Object} - * `device` {string} The specified path for `spidev`. + * `device` {string} The specified path for `spidev`. (only on Linux) + * `bus` {number} The specified bus number. (Tizen, TizenRT and NuttX only) * `mode` {SPI.MODE} The combinations of the polarity and phase. **Default:** `SPI.MODE[0]`. * `chipSelect` {SPI.CHIPSELECT} Chip select state. **Default:** `SPI.CHIPSELECT.NONE`. * `maxSpeed` {number} Maximum transfer speed. **Default:** `500000`. @@ -51,7 +52,8 @@ Sets the order of the bits shifted out of and into the SPI bus, either MSB (most * `loopback` {boolean} Using loopback. **Default:** `false`. * `callback` {Function}. * `err` {Error|null}. -* Returns: {SPIBus}. + * `spibus` {Object} An instance of SPIBus. +* Returns: {Object} An instance of SPIBus. Opens an SPI device with the specified configuration. @@ -59,8 +61,7 @@ Opens an SPI device with the specified configuration. ```js -var Spi = require('spi'); -var spi = new Spi(); +var spi = require('spi'); var spi0 = spi.open({ device: '/dev/spidev0.0' }, function(err) { @@ -71,18 +72,43 @@ var spi0 = spi.open({ ``` +### spi.openSync(configuration) +* `configuration` {Object} + * `device` {string} The specified path for `spidev`. (only on Linux) + * `bus` {number} The specified bus number. (Tizen, TizenRT and NuttX only) + * `mode` {SPI.MODE} The combinations of the polarity and phase. **Default:** `SPI.MODE[0]`. + * `chipSelect` {SPI.CHIPSELECT} Chip select state. **Default:** `SPI.CHIPSELECT.NONE`. + * `maxSpeed` {number} Maximum transfer speed. **Default:** `500000`. + * `bitsPerWord` {number} Bits per word to send (should be 8 or 9). **Default:** `8`. + * `bitOrder` {SPI.BITORDER} Order of the bits shifted out of and into the SPI bus. Default: `SPI.BITORDER.MSB`. + * `loopback` {boolean} Using loopback. **Default:** `false`. +* Returns: {Object} An instance of SPIBus. + +Opens an SPI device with the specified configuration. + +**Example** + +```js + +var spi = require('spi'); +var spi0 = spi.openSync({ + device: '/dev/spidev0.0' +}); + +``` + ## Class: SPIBus The SPIBus is commonly used for communication. -### spibus.transfer(txBuffer, rxBuffer[, callback]) +### spibus.transfer(txBuffer, [, callback]) * `txBuffer` {Array|Buffer}. -* `rxBuffer` {Array|Buffer}. * `callback` {Function}. * `err` {Error|null}. + * `rxBuffer` {Array}. Writes and reads data from the SPI device asynchronously. -The `txBuffer` and `rxBuffer` must have equal length. +The `txBuffer` and `rxBuffer` length is equal. **Example** @@ -90,7 +116,7 @@ The `txBuffer` and `rxBuffer` must have equal length. var tx = new Buffer('Hello IoTjs'); var rx = new Buffer(tx.length); -spi0.transfer(tx, rx, function(err) { +spi0.transfer(tx, function(err, rx) { if (err) { throw err; } @@ -104,20 +130,19 @@ spi0.transfer(tx, rx, function(err) { ``` -### spibus.transferSync(txBuffer, rxBuffer) +### spibus.transferSync(txBuffer) * `txBuffer` {Array|Buffer}. -* `rxBuffer` {Array|Buffer}. +* Returns: `rxBuffer` {Array}. Writes and reads data from the SPI device synchronously. -The `txBuffer` and `rxBuffer` must have equal length. +The `txBuffer` and `rxBuffer` length is equal. **Example** ```js var tx = new Buffer('Hello IoTjs'); -var rx = new Buffer(tx.length); -spi0.transferSync(tx, rx); +var rx = spi0.transferSync(tx); var value = ''; for (var i = 0; i < tx.length; i++) { value += String.fromCharCode(rx[i]); diff --git a/docs/api/IoT.js-API-Stream.md b/docs/api/IoT.js-API-Stream.md index 97ccddc36c..2d6a892e39 100644 --- a/docs/api/IoT.js-API-Stream.md +++ b/docs/api/IoT.js-API-Stream.md @@ -2,14 +2,14 @@ The following shows stream module APIs available for each platform. -| | Linux
(Ubuntu) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | -| :---: | :---: | :---: | :---: | -| readable.isPaused | O | O | O | -| readable.pause | O | O | O | -| readable.read | O | O | O | -| readable.resume | O | O | O | -| writable.end | O | O | O | -| writable.write | O | O | O | +| | Linux
(Ubuntu) | Tizen
(Raspberry Pi) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | TizenRT
(Artik053) | +| :---: | :---: | :---: | :---: | :---: | :---: | +| readable.isPaused | O | O | O | O | O | +| readable.pause | O | O | O | O | O | +| readable.read | O | O | O | O | O | +| readable.resume | O | O | O | O | O | +| writable.end | O | O | O | O | O | +| writable.write | O | O | O | O | O | # Stream @@ -270,6 +270,116 @@ console.log(readable.read()); ``` +### readable.pipe(destination[, options]) +* `destination` {Writable|Duplex} +* `options` + * `end` {bool} **Default: `true`** +* returns: {Writable|Duplex} + +Attaches a Writable or Duplex stream to the Readable. Automatically +switches the Readable stream into flowing mode and pushes all of its +data into the attached Writable. + +**Example** +```js +var stream = require('stream'); +var Readable = stream.Readable; +var Writable = stream.Writable; + +var source = new Readable(); +var dest = new Writable(); + +dest._write = function(chunk, callback, onwrite) { + console.log('dest received: ', chunk.toString()); +}; +dest._readyToWrite(); + +source.pipe(dest); +source.push('hello'); // the dest._write function will print the data +``` + +It is also possible to attach multiple Writable streams to a single +Readable stream. +The `readable.pipe()` method returns a reference to the `destination` stream, +making it possible to set up a chain of piped streams +(only if `destination` is Duplex). + +**Example** +```js +var stream = require('stream'); +var Readable = stream.Readable; +var Writable = stream.Writable; + +var source = new Readable(); +var dest = new Duplex(); +var dest2 = new Duplex(); + +dest._write = function(chunk, callback, onwrite) { + console.log('dest received: ', chunk.toString()); +}; +dest._readyToWrite(); + +dest2._write = function(chunk, callback, onwrite) { + console.log('dest2 received: ', chunk.toString()); +}; +dest2._readyToWrite(); + +source.pipe(dest).pipe(dest2); +source.push('hello'); // dest and dest2 will receive and print the data +``` + +By default, the `end()` method of the `destination` stream is called when the +Readable emits `end`. This behavior can be disabled by passing the `end` +option as `false` to the `Readable.pipe()` method. + +Note: in case of a stream error, the attached streams will NOT be closed +automatically. If a stream error occurs, each of the attached streams must +be closed manually. + + +### readable.unpipe([destination]) +* `destination` {Writable|Duplex} +* returns: `this` + +Detaches a previously attached stream from the Readable. +If the optional `destination` argument is not specified, all attached streams +will be detached. +If `destination` is specified but there is no pipe set up for it, then the +method simply returns and does nothing. + +**Example** +```js +var stream = require('stream'); +var Readable = stream.Readable; +var Writable = stream.Writable; + +var source = new Readable(); +var dest = new Writable(); + +dest._write = function(chunk, callback, onwrite) { + console.log('dest received: ', chunk.toString()); +}; +dest._readyToWrite(); + +source.pipe(dest); +source.push('hello'); // the dest._write function will print the data +source.unpipe(dest); // source.unpipe() has the same effect in this case +source.push(world); // dest will not receive the data anymore +``` + +Note: if multiple streams are piped together in a chain, unpiping the first one +from the readable will not unpipe the rest of them. + +**Example** +```js +source.pipe(dest).pipe(dest2).pipe(dest3).pipe(dest4); +// ... some code ... +source.unpipe(dest); +// dest will no longer be piped to source, but dest2 will still be +// piped to dest, etc +``` + + # Class: Stream.Writable Writable stream is an abstraction for a *destination* diff --git a/docs/api/IoT.js-API-TLS.md b/docs/api/IoT.js-API-TLS.md new file mode 100644 index 0000000000..42b4bcc2a9 --- /dev/null +++ b/docs/api/IoT.js-API-TLS.md @@ -0,0 +1,195 @@ +### Platform Support + +The following chart shows the availability of each TLS module API function on each platform. + +| | Linux
(Ubuntu) | Tizen
(Raspberry Pi) | Raspbian
(Raspberry Pi) | Nuttx
(STM32F4-Discovery) | TizenRT
(Artik053) | +| :---: | :---: | :---: | :---: | :---: | :---: | +| tls.connect | O | O | O | O | O | O | +| tls.createServer | O | O | O | O | O | O | +| tls.createSecureContext | O | O | O | O | O | O | +| tls.Server | O | O | O | O | O | O | +| tls.TLSSocket | O | O | O | O | O | O | +| tls.TLSSocket.write | O | O | O | O | O | O | +| tls.TLSSocket.pause | O | O | O | O | O | O | +| tls.TLSSocket.end | O | O | O | O | O | O | +| tls.TLSSocket.resume | O | O | O | O | O | O | +| tls.TLSSocket.pause | O | O | O | O | O | O | + +As even a couple of sockets/servers/requests require a considerable size of memory, on NuttX/STM32F4-Discovery and TizenRT/Artik053 +the number of such sockets are limited. + +# TLS + +Transport Layer Security makes secure communication over sockets possible. + +### tls.connect(options[,callback]) +* `options` {Object} + * `host` {string} Host the client should connect to, defaults to 'localhost'. + * `port` {number} Port the client should connect to. + * `socket` {stream.Duplex} Optional, typically an instance of `net.Socket`. If this options is specified, host and port are ignored. The user passing the options is responsible for it connecting to the server. `tls.connect` won't call `net.connect` on it. + * `rejectUnauthorized` {boolean} Whether the server certificate should be verified against the list of supplied CAs. An `error` event is emitted if verifications fails; `err.code` contains the MbedTLS error code. Defaults to `false`. NOT READY + * `servername` {string} Server name for the SNI (Server name Indication) TLS extension. NOT READY + * `session` {Buffer} A `Buffer` containing a TLS session. NOT READY + * `minDHSize` {number} The minimum size of the DH parameter in bits to accept a TLS connection. If a server offers a DH parameter with a size less than specified, the TLS connection is destroyed and an error is thrown. Defaults to `1024`. + * `lookup` {Function} Custom lookup. Defaults to `dns.lookup()`. +* `callback` {Function} The callback function will be added as a listener for the `secureConnect` event. + +Returns a `tls.TLSSocket` object. + +**Example** + +```js +var tls = require('tls'); + +var opts = { + host: '127.0.0.1', + port: 443, + rejectUnauthorized: true +} + +var socket = tls.connect(opts, function() { + socket.write('Hello IoT.js'); + socket.end(); +}); +``` + +### tls.connect(port[,host][,options][,callback]) +* `port` {number} Port the client should connect to. +* `host` {string} Host the client should connect to, defaults to 'localhost'. +* `options` {Object} See `tls.connect()`. +* `callback` {Function} See `tls.connect()`. + +Same as tls.connect() except that port and host can be provided as arguments instead of options. +A port or host option, if specified, will take precedence over any port or host argument. + +**Example** + +```js +var tls = require('tls'); + +var socket = tls.connect(443, 'localhost', function() { + socket.write('Hello IoT.js'); + socket.end(); +}); +``` + +### tls.createServer([options][, secureConnectionListener]) +* `options` {object} Accepts the same options as the `tls.Server()` and `tls.createSecureContext()`. +* `secureConnectionListener` {Function} + * `socket` {tls.TLSSocket} The connected TLSSocket. +* Returns {tls.Server} + +Create a TLS Server. Behaves the same way as the `new tls.Server(options, secureConnectionListener)` +call. + +**Example** + +```js + +var fs = require('fs'); +var tls = require('tls'); +var options = { + key: fs.readFileSync('server.key'), + cert: fs.readFileSync('server.crt') +}; +var server = tls.createServer(options, function(socket) { + console.log('got connection'); + ... +}); + +server.listen(8081); +``` + + +### tls.createSecureContext([options]) +* `options` {object} + * `ca` {string | Buffer} Optional trusted CA certificates. No default is provided. + * `cert` {string | Buffer} Cert chains in PEM format. + * `key` {string | Buffer} Private keys in PEM format. +* Returns {Object} + +The method returns a special object containing the tls context and credential information. + +## Class: tls.Server + +A server object representing a TLS server. Based on the `net.Server`. +All events, methods and properties are inherited from the `net.Server`. + +### new tls.Server([options][, secureConnectionListener]) + +* `options` {object} Options for the TLS connection. + * `secureContext` {object} An special object containing the tls credential information. + This should be only created via a `tls.createSecureContext()` call if needed. If not provided + a secureContext will be created automatically, using the `options` object. No default value is provided. + * Additional options are from `tls.createSecureContext()`. +* `secureConnectionListener` {Function} + * `socket` {tls.TLSSocket} +* Returns {tls.Server} + +Creates new `tls.Server` object. The `secureConnectionListener` method is automatically set +as a listener for the `'secureConnection'` event. + +To correctly create a TLS Server the server certificates should be provided in the `options` +object. + +**Example** + +```js +var fs = require('fs'); +var tls = require('tls'); +var options = { + key: fs.readFileSync('server.key'), + cert: fs.readFileSync('server.crt') +}; +var server = new tls.Server(options, function(socket) { + console.log('got connection'); + ... +}); + +server.listen(8081); +``` + +## Class: tls.TLSSocket +The `TLSSocket` is responsible for all TLS negotiations and data encryption on a `net.Socket`. + +Just like `net.Socket` it uses a `Stream.duplex` interface. + +### new tls.TLSSocket(socket[,options]) +* `socket` {net.Socket | stream.Duplex} +* `options` {Object} + * `isServer` {boolean} The TLSSocket must know if it represents the server or client side of the connection. Default: `false`. + * `secureContext` {Object} The TLS context object. If none provided one will be created with the `tls.createSecureContext` method + using the given `options` object. +* Returns {tls.TLSSocket} + +Creates a new TLSSocket object for an existing TCP socket. + +### tlsSocket.address() +Returns an object containing the bound address, family name, and port of the socket.`{port: 443, family: 'IPv4', address: '127.0.0.1'}` + +### tlsSocket.authorizationError +Returns the reason why the peer's certificate has not been verified. + +### tlsSocket.authorized +Returns `true` if the peer certificate was signed by one of the CAs specified when creating the `tls.TLSSocket` instance, otherwise false. + +### tlsSocket.encrypted +Always returns `true`, can be used to distinguish TLS sockets from regular `net.Socket`s. + +### tlsSocket.getProtocol() +Returns a string containing the negotiated SSL/TLS protocol version of the connection. If the handshaking has not been complete, `unknown` will be returned. The value `null` will be returned for server sockets or disconnected client sockets. + +### tlsSocket.localAddress +Returns a string representing the local IP address. + +### tlsSocket.localPort +Returns a number representing the local port. + +### tlsSocket.remoteAddress +Returns a string representing the remote IP address. + +### tlsSocket.remoteFamily +Returns a string representing the remote IP family. + +### tlsSocket.remotePort +Returns a number representing the remote port. diff --git a/docs/api/IoT.js-API-Timers.md b/docs/api/IoT.js-API-Timers.md index ee436434da..0c6af713c5 100644 --- a/docs/api/IoT.js-API-Timers.md +++ b/docs/api/IoT.js-API-Timers.md @@ -2,12 +2,12 @@ The following shows timer module APIs available for each platform. -| | Linux
(Ubuntu) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | -| :---: | :---: | :---: | :---: | -| setTimeout | O | O | O | -| clearTimeout | O | O | O | -| setInterval | O | O | O | -| clearInterval | O | O | O | +| | Linux
(Ubuntu) | Tizen
(Raspberry Pi) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | TizenRT
(Artik053) | +| :---: | :---: | :---: | :---: | :---: | :---: | +| setTimeout | O | O | O | O | O | +| clearTimeout | O | O | O | O | O | +| setInterval | O | O | O | O | O | +| clearInterval | O | O | O | O | O | # Timers @@ -89,4 +89,4 @@ When called, requests that the IoT.js event loop should not exit as long as the ### timeout.unref() -When called, the active `Timeout` object will not force the IoT.js event loop to remain active. If there are no other scheduled activites, the process may exit, the process may exit before the `Timeout` object's callback is invoked. +When called, the active `Timeout` object will not force the IoT.js event loop to remain active. If there are no other scheduled activities, the process may exit, the process may exit before the `Timeout` object's callback is invoked. diff --git a/docs/api/IoT.js-API-UART.md b/docs/api/IoT.js-API-UART.md index b71f00e947..34b033cbb0 100644 --- a/docs/api/IoT.js-API-UART.md +++ b/docs/api/IoT.js-API-UART.md @@ -2,25 +2,25 @@ The following shows uart module APIs available for each platform. -| | Linux
(Ubuntu) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | -| :---: | :---: | :---: | :---: | -| uart.open | O | O | O | -| uartport.write | O | O | O | -| uartport.writeSync | O | O | O | -| uartport.close | O | O | X | -| uartport.closeSync | O | O | X | +| | Linux
(Ubuntu) | Tizen
(Raspberry Pi) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | TizenRT
(Artik053) | +| :---: | :---: | :---: | :---: | :---: | :---: | +| uart.open | O | O | O | O | O | +| uart.openSync | O | O | O | O | O | +| uartport.write | O | O | O | O | O | +| uartport.writeSync | O | O | O | O | O | +| uartport.close | O | O | O | O | O | +| uartport.closeSync | O | O | O | O | O | ## Class: UART The UART (Universal Asynchronous Receiver/Transmitter) class supports asynchronous serial communication. -### new UART() +* On Tizen, the port number is defined in [this documentation](../targets/tizen/SystemIO-Pin-Information-Tizen.md#uart). -Returns with a new UART object. - -### uart.open(configuration[, callback]) +### uart.open(configuration, callback) * `configuration` {Object} - * `device` {string} Mandatory configuration. + * `device` {string} Mandatory configuration. The specified device path.(Linux, Nuttx and TizenRT only) + * `port` {number} Mandatory configuration. The specified port number. (Tizen only) * `baudRate` {number} Specifies how fast data is sent over a serial line. **Default:** `9600`. * `dataBits` {number} Number of data bits that are being transmitted. **Default:** `8`. * `callback` {Function}. @@ -40,10 +40,8 @@ You can read more information about the usage of the UART on stm32f4-discovery b **Example** ```js +var uart = require('uart'); -var Uart = require('uart'); - -var uart = new Uart(); var configuration = { device: '/dev/ttyUSB0' baudRate: 115200, @@ -54,12 +52,41 @@ var serial = uart.open(configuration, function(err) { // Do something. }); +serial.closeSync(); + +``` + +### uart.openSync(configuration) +* `configuration` {Object} + * `device` {string} Mandatory configuration. The specified device path. (Linux, Nuttx and TizenRT only) + * `port` {number} Mandatory configuration. The specified port number. (Tizen only) + * `baudRate` {number} Specifies how fast data is sent over a serial line. **Default:** `9600`. + * `dataBits` {number} Number of data bits that are being transmitted. **Default:** `8`. +* Returns: {UARTPort}. + +Opens an UARTPort object with the specified configuration. + +**Example** + +```js +var uart = require('uart'); + +var configuration = { + device: '/dev/ttyUSB0' + baudRate: 115200, + dataBits: 8, +} + +var serial = uart.openSync(configuration); + +serial.closeSync(); + ``` ## Class: UARTPort The UARTPort class is responsible for transmitting and receiving serial data. -### uartport.write(data[, callback]). +### uartport.write(data, callback). * `data` {string}. * `callback` {Function}. * `err` {Error|null}. @@ -69,12 +96,13 @@ Writes the given `data` to the UART device asynchronously. **Example** ```js +var serial = uart.openSync({device: '/dev/ttyUSB0'}); serial.write('Hello?', function(err) { if (err) { // Do something. } - serial.close(); + serial.closeSync(); }); ``` @@ -87,10 +115,9 @@ Writes the given `data` to the UART device synchronously. **Example** ```js - +var serial = uart.openSync({device: '/dev/ttyUSB0'}); serial.writeSync('Hello?'); - -serial.close(); +serial.closeSync(); ``` @@ -100,19 +127,13 @@ serial.close(); Closes the UART device asynchronously. -On NuttX/STM32F4Discovery, Uart.close() blocks after close(). -It seems that poll() does not work properly on NuttX for some cases. - ### uartport.closeSync() Closes the UART device synchronously. -On NuttX/STM32F4Discovery, Uart.close() blocks after close(). -It seems that poll() does not work properly on NuttX for some cases. - ### Event: 'data' * `callback` {Function} - * `data` {string} A string from the sender. + * `data` {Buffer} A data from the sender. **Example** diff --git a/docs/api/IoT.js-API-WebSocket.md b/docs/api/IoT.js-API-WebSocket.md new file mode 100644 index 0000000000..5cf9296340 --- /dev/null +++ b/docs/api/IoT.js-API-WebSocket.md @@ -0,0 +1,263 @@ +### Platform Support + +The following chart shows the availability of each WebSocket module API function on each platform. + +| | Linux
(Ubuntu) | Tizen
(Raspberry Pi) | Raspbian
(Raspberry Pi) | Nuttx
(STM32F4-Discovery) | TizenRT
(Artik053) | +| :---: | :---: | :---: | :---: | :---: | :---: | +| websocket.connect | O | O | O | X | O | +| websocket.close | O | O | O | X | O | +| websocket.ping | O | O | O | X | O | +| websocket.send | O | O | O | X | O | + +# WebSocket + +WebSocket provides full-duplex communication over a TCP connection. It is designed to work over HTTP ports 80 and 443. + +### Requirements +WebSocket requires you to enable both the `TLS` and the `WebSocket` module. This can be done by compiling IoT.js with `--cmake-param=-DENABLE_MODULE_WEBSOCKET=ON`. Currently WebSocket only works if TLS is enabled as well. + +## Class: Websocket.Server +Create a new Websocket server instance. + +### Websocket.Server(options[, callback]) +Create a new server instance. One of `port` or `server` must be provided or an error is thrown. An HTTP server is automatically created, started, and used if `port` is set. If `secure` is set TLS server is automatically created, started and used. The `tls` module is required or an error is thrown. To use an external HTTP/S server instead, specify only `server`. In this case the HTTP/S server must be started manually. + +- `options` {Object} + - `port` {Number} + - `host` {String} Optional. Defaults to `localhost`. + - `server` {Object} Optional. + - `path` {String} Optional. Defaults to `/`. + - `secure` {Boolean} Optional. + - `key` {String} Optional. (Required on `secure` server) + - `cert` {String} Optional. (Required on `secure` server) +- `callback` {Function} Optional. The function which will be executed when the client successfully connected to the server. + +Emits a `connection` event when the connection is established. + +**Example** +```js +var websocket = require('websocket'); + +var options = { + port: 9999 +} + +var server = new websocket.Server(options, Listener); + +function Listener(ws) { + console.log('Client connected: handshake done!'); + ws.on('message', function (msg) { + console.log('Message received: %s', msg.toString()); + ws.send(msg.toString(), {mask: true, binary: false}); //echo + server.close(); + }); + ws.on('ping', function (msg) { + console.log('Ping received: %s', msg.toString()); + }); + ws.on('close', function (msg) { + console.log('Client close :\n' + 'Reason: ' + msg.reason + ' Code: ' + msg.code); + }); + ws.on('error', function (msg) { + console.log('Error: %s', msg.toString()); + }); + +server.broadcast('Message to all clients', {mask: false, binary: false}); +}; + +server.on('error', function (msg) { + console.log('Error: %s', msg.toString()); +}); + +server.on('close', function (msg) { + console.log('Server close: \nReason: ' + + msg.reason + ' Code: ' + msg.code); +}); +``` + +**Example using http server** +```js +var websocket = require('websocket'); +var http = require('http'); + +var httpserver = http.createServer().listen(9999); + +options = { + server: httpserver +}; + +var wss3 = new websocket.Server(options, Listener); + +function Listener(ws) { + console.log('Client connected: handshake done!'); +}; +``` + +### server.address() + +Returns an object with `port`, `family`, and `address` properties specifying +the bound address, the family name, and port of the server. + +**Example** +```js +var websocket = require('websocket'); + +var options = { + port: 9999 +} + +var server = new websocket.Server(options, function(ws) { +}); + +console.log(server.address()); +``` + +### server.close([reason], [code]) +You can specify a close message and a close code as well. More info on them can be read here: [https://tools.ietf.org/html/rfc6455#section-7.4.1](https://tools.ietf.org/html/rfc6455#section-7.4.1 "The WebSocket Protocol Status Codes") + +- `reason` {String} Optional. Defaults to `Connection successfully closed`. +- `code` {Number} Optional. Defaults to `1000`. + +Close the Websocket server, terminate all clients and emit the `close` event. + +**Example** +```js +var websocket = require('websocket'); + +var options = { + port: 9999 +} + +var server = new websocket.Server(options, Listener); + +function Listener(ws) { + console.log('Client connected: handshake done!'); + server.close('Connection successfully closed', 1000); +}; +``` + +### server.broadcast(message [, options]) +You can specify a message that will be sent to every clients. +The `mask` will specify whether the data frame should be masked or not. +The `binary` will specify that if the data frame mode should be text or binary, default to text. +More info on them can be read here: [https://tools.ietf.org/html/rfc6455#section-5.6](https://tools.ietf.org/html/rfc6455#section-5.6 "The WebSocket Protocol Data Frames") + +- `message` {String} +- `options` {Object} Optional. + - `mask` {Boolean} Optional. Defaults to `true`. + - `binary` {Boolean} Optional. Defaults to `false`. + +Send message to all clients. + +**Example** +```js +var websocket = require('websocket'); + +var options = { + port: 9999 +} + +var server = new websocket.Server(options, Listener); + +function Listener(ws) { + console.log('Client connected: handshake done!'); +}; + +server.broadcast('Message to receive all client', + {mask: true, binary: false}); +``` + +### Event: 'connection' + +- `socket` {Websocket} + +Emitted when the handshake is complete. + +### Event: 'close' + +- `message` {Object} + - `reason` {String} + - `code` {Number} + +Emitted when the server close. + +### Event: 'error' + +- `error` {Error} + +Emmitted when an error occurs on the server. + +## Class: Websocket +The `Websocket` client can simultaneously receive and send data. Both `net` and `TLS` sockets are supported, however the latter is recommended, since `websocket` itself doesn't provide a secure enough context to communicate sensitive data. + +### websocket.connect([host], [port], [path], [callback]) +Connects to a `websocket` server, host names can be prefixed with `ws://` or `wss://`. +- `host` {string} Optional. Defaults to `localhost`. +- `port` {number} Optional. Defaults to `80` if the `host` begins with `ws://` or `443` with `wss://`. +- `path` {Buffer | string} Optional. Defaults to `/`. If given, the client connects to that `endpoint`. +- `callback` {function} Optional. The function which will be executed when the client successfully connected to the server. + +Emits an `open` event when the connection is established. + +**Example** +```js +var ws = require('websocket'); + +var my_websocket = new ws.Websocket(); + +my_websocket.connect('wss://127.0.0.1', 443, '/my_endpoint', function() { + my_websocket.close('Successful connection', 1000); +}); + +``` + +### websocket.close([message], [code], [callback]) +Closes the `websocket` connection with the server. You can specify a close `message` and a close `code` as well. More info on them can be read here: https://tools.ietf.org/html/rfc6455#section-7.4.1 +- `message` {Buffer | string} Optional. This `message` is sent to the server as a close message, mostly for explaining the status `code`. +- `code` {number} Optional. The `code` indicates the reason why the `websocket` connection was closed. Defaults to 1000. +- `callback` {function} Optional. The function will be executed when the `websocket` connection is closed. + +Emits a `close` event when the connection is closed. + +### websocket.ping([message], [mask], [callback]) +Sends a `ping` to the server. If there is no response in the next 30 seconds, the connection is closed. +- `message` {Buffer | string} Optional. The `message` is used to identify the `ping` frame. +- `mask` {boolean} Optional. Defaults to `false`. Sets to mask the `message` or not. +- `callback` {function} Optional. The function to be executed when the server sends a response to the `ping`. + +**Example** +```js +my_websocket.ping('Ping frame 1', true, function(msg) { + console.log('Pong frame successfully received for frame ' + msg); +}); + +``` + +### websocket.send([message], [options], [callback]) +Sends data to the server. It can be either `binary` or `utf8` data. +- `message` {Buffer | string} The `message` to be sent to the server. +- `options` {Object} + - `mask` {boolean} Optional. Defaults to `false`. If set, the `message` is masked. + - `binary` {boolean} Optional. Defaults to `false`. If set, the `message` is expected to be binary data. +- `callback` {function} Optional. The function to be executed when the `frame` is successfully sent. + +**Example** +```js +my_websocket.send('My first WebSocket message!', {mask: true, binary: false}, function() { + console.log('The data was successfully written to the socket!'); +}); +``` + +## Events + +### `close` +Having closed the `websocket` connection, with the server, a `close` is emitted. + +### `error` +If an `error` occurs, the `error` event is emitted, with the corresponding error message. + +### `message` +The `message` event is emitted when the client receives data from the server. + +### `open` +Emitted when the client established a `websocket` connection with the server. diff --git a/docs/api/IoT.js-API-reference.md b/docs/api/IoT.js-API-reference.md index 1366db33a7..c0fad9bbaf 100644 --- a/docs/api/IoT.js-API-reference.md +++ b/docs/api/IoT.js-API-reference.md @@ -15,9 +15,11 @@ * [(ADC)](IoT.js-API-ADC.md) * [(BLE)](IoT.js-API-BLE.md) * [(GPIO)](IoT.js-API-GPIO.md) +* [HTTPS](IoT.js-API-HTTPS.md) * [(I2C)](IoT.js-API-I2C.md) * [(PWM)](IoT.js-API-PWM.md) * [(SPI)](IoT.js-API-SPI.md) +* [TLS](IoT.js-API-TLS.md) * [(UART)](IoT.js-API-UART.md) * [UDP/Datagram](IoT.js-API-DGRAM.md) diff --git a/docs/build/Build-Script.md b/docs/build/Build-Script.md index aee48b3688..7a2c38535b 100644 --- a/docs/build/Build-Script.md +++ b/docs/build/Build-Script.md @@ -4,7 +4,7 @@ build.py help you build IoT.js. It locates in "./tools" directory of source tree. -It automatically creates a directory where build object and outputs will be generated, +It automatically creates a directory where build object and outputs will be generated, checks configurations, tidiness of source code, licenses, and more. Also it downloads, updates and builds submodules. And finally generate IoT.js binary. @@ -16,17 +16,17 @@ You can build IoT.js with default setting for your host machine with; ``` ./tools/build.py ``` -The command will generate runnable IoT.js binary in "./build//debug/iotjs/iotjs". +The command will generate runnable IoT.js binary in "./build//debug/bin/iotjs". You can also build release binary with; ``` ./tools/build.py --buildtype=release ``` -## Parameters Candidates -**NOTE: some parameters are not supported by current version of build.py** +### Arguments of IoT.js +The following arguments are related to the IoT.js framework. --- +--- #### `--buildtype` * `release` | `debug` @@ -36,7 +36,7 @@ Specify whether build output will be for 'debug' or 'release'. ./tools/build.py --buildtype=release ``` --- +--- #### `--builddir` Specify a directory where build outputs will be generated. @@ -47,72 +47,95 @@ If given path is not exist, build.py will create it. ./tools/build.py --builddir=./build ``` --- -#### `--clean` -With given this option, build.py will clear all the build directory before start new build. +--- +#### `--buildlib` +With given this option, build.py will generate IoT.js output as a library. ``` -./tools/build.py --clean +./tools/build.py ---buildlib ``` --- -#### `--buildlib` -With given this option, build.py will generate IoT.js output as a library. +--- +#### `--cmake-param` +Specify CMake parameters for IoT.js. + +"cmake" command for IoT.js will be executed with the given parameter applied. + +If you have multiple parameters, supply it with multiple use of this option; ``` -./tools/build.py ---buildlib +./tools/build.py --cmake-param="..." --cmake-param="..." ``` --- -#### `--target-arch` -* `arm` | `x86` | `i686` | `x86_64` | `x64` +--- +#### `--compile-flag` +Specify C compiler flags for IoT.js. -Specify target architecture. +If you have multiple compile flags, supply it with multiple use of this option; +``` +./tools/build.py --compile-flag="..." --compile-flag="..." +``` + +--- +#### `--clean` +With given this option, build.py will clear all the build directory before start new build. ``` -./tools/build.py --target-arch=arm +./tools/build.py --clean ``` --- -#### `--target-os` -* `linux` | `darwin` | `osx` | `nuttx` -Specify target OS. +--- +#### `--config` +Specify build configuration file path. ``` -./tools/build.py --target-os=nuttx --target-arch=arm +./tools/build.py --config=build.arm.nuttx.stm32f4dis.config ``` --- -#### `--target-board` -* `stm32f4dis` | empty +`build.default.config` file is in the source tree for default setting. -Specify target board. +If this option is not specified, `build.config` file will be applied. If the file does not exist, it will be copied from `build.default.config`. + +Parameters specified by the config file is applied, and then the parameters given by command line overwrite over the settings. + +If you need to apply the same set of parameters for each build, making your own config file and trigger build.py with the config file would be more convenient. + +--- +#### `-e, --experimental` +Enable to build experimental features ``` -./tools/build.py --target-os=nuttx --target-arch=arm --target-board=stm32f4dis +./tools/build.py --experimental ``` --- -#### `--cmake-param` -Specify CMake parameters for IoT.js. -"cmake" command for IoT.js will be executed with the given parameter applied. +--- +#### `--external-include-dir` +Specify external include directory for IoT.js. -If you have multiple parameters, supply it with multiple use of this option; +If you have multiple external include directoies, supply it with multiple use of this option; +``` +./tools/build.py --external-include-dir="..." --external-include-dir="..." +``` + +--- +#### `--external-lib` +Specify external library that will be linked with IoT.js. +If you have multiple such libraries, supply it with multiple use of this option; ``` -./tools/build.py --cmake-param="..." --cmake-param="..." +./tools/build.py --external-lib="libxxx" ``` --- -#### `--compile-flag` -Specify C compiler flags for IoT.js. +--- +#### `--external-modules` +Specify the path of modules.json files which should be processed (format: path1,path2,...). +See also: ["How to write a new module"](../devs/Writing-New-Module.md) -If you have multiple compile flags, supply it with multiple use of this option; ``` -./tools/build.py --compile-flag="..." --compile-flag="..." +./tools/build.py --external-modules=/home/iotjs/my-modules-directory ``` --- +--- #### `--link-flag` Specify linker flags for IoT.js. @@ -121,25 +144,100 @@ If you have multiple link flags, supply it with multiple use of this option; ./tools/build.py --link-flag="..." --link-flag="..." ``` --- -#### `--external-include-dir` -Specify external include directory for IoT.js. +--- +#### `--no-check-valgrind` +Disable test execution with valgrind after build. -If you have multiple external include directoies, supply it with multiple use of this option; ``` -./tools/build.py --external-include-dir="..." --external-include-dir="..." +./tools/build.py --no-check-valgrind ``` --- -#### `--external-static-lib` -Specify external static library that will be liked with IoT.js statically. +--- +#### `--no-init-submodule` +With given this option, submoduls will not initialized before start build. -If you have multiple such libraries, supply it with multiple use of this option; ``` -./tools/build.py --external-static-lib="libxxx.a" +./tools/build.py --no-init-submodule ``` --- +--- +#### `--no-parallel-build` +With given this option, compilation process will not run in parallel. In other words, executes `make` without `-j` option. + +``` +./tools/build.py --no-parallel-build +``` + +--- +#### `--nuttx-home` +To build for nuttx os, nuttx home directory must be given. + +``` +./tools/build.py --target-os=nuttx --target-arch=arm --target-board=stm32f4dis --nuttx-home="..." +``` + +--- +#### `--profile` +With given this option, build.py will use the specified profile for the build. +See also: ["How to write a new module"](../devs/Writing-New-Module.md#profile) + +``` +./tools/build.py --profile=./profiles/minimal.profile +``` + +--- +#### `--run-test` +* `full` | `quiet` + +Execute tests after build, optional argument specifies the level of output for the testrunner. + +``` +./tools/build.py --run-test=full +``` + +--- +#### `--sysroot` +The location of the development tree root directory (sysroot). Must be compatible with used toolchain. + +``` +./tools/build.py --sysroot=/home/iotjs/sysroot-directory +``` + +--- +#### `--target-arch` +* `arm` | `x86` | `i686` | `x86_64` | `x64` | `mips` | `noarch` + +Specify target architecture. + +``` +./tools/build.py --target-arch=arm +``` + +--- +#### `--target-board` +* `artik10` | `artik05x` | `rpi2` | `rpi3` | `stm32f4dis` | empty + +Specify target board. + +``` +./tools/build.py --target-os=nuttx --target-arch=arm --target-board=stm32f4dis +``` + +--- +#### `--target-os` +* `linux` | `darwin` | `osx` | `nuttx` | `tizen` | `tizenrt` | `openwrt` + +Specify target OS. + +``` +./tools/build.py --target-os=nuttx --target-arch=arm +``` + + +### 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-cmake-param` Specify CMake parameters for JerryScript. @@ -147,7 +245,7 @@ Specify CMake parameters for JerryScript. If you have multiple parameters, supply it with multiple use of this option --- +--- #### `--jerry-compile-flag` Specify C compiler flags for JerryScript. @@ -157,13 +255,15 @@ If you have multiple cflags, supply it with multiple use of this option ./tools/build.py --jerry-compile-flag="-DCONFIG_ECMA_LCACHE_DISABLE" ``` --- -#### `--jerry-link-flag` -Specify linker flags for JerryScript. +--- +#### `--jerry-debugger` +Enable JerryScript debugger. See also ["Use JerryScript Debugger"](../devs/Use-JerryScript-Debugger.md). -If you have multiple ldflags, supply it with multiple use of this option +``` +./tools/build.py --jerry-debugger +``` --- +--- #### `--jerry-heaplimit` Specify object heap limit for JerryScript engine. @@ -171,15 +271,15 @@ Specify object heap limit for JerryScript engine. ./tools/build.py --jerry-heaplimit=80 ``` --- -#### `--jerry-memstat` -Enable memstat of JerryScript engine. +--- +#### `--jerry-heap-section` +Specify the name of the JerryScript heap section. ``` -./tools/build.py --jerry-memstat +./tools/build.py --jerry-heap-section=".ARM.__at_0x20000" ``` --- +--- #### `--jerry-lto` With given this option, JerryScript will be built with LTO. @@ -187,58 +287,38 @@ With given this option, JerryScript will be built with LTO. ./tools/build.py --jerry-lto ``` --- -#### `--no-init-submodule` -With given this option, submoduls will not initialized before start build. - -``` -./tools/build.py --no-init-submodule -``` - --- -#### `--no-check-tidy` -With given this option, tidy checking will not performed. +--- +#### `--jerry-memstat` +Enable memstat of JerryScript engine. ``` -./tools/build.py --no-check-tidy +./tools/build.py --jerry-memstat ``` --- -#### `--no-check-test` -With given this option, unit test checking will not performed. +--- +#### `--jerry-profile` +* `es5.1` | `es2015-subset | absolute path to a custom profile file` -``` -./tools/build.py --no-check-test -``` - --- -#### `--no-parallel-build` -With given this option, compilation process will not run in parallel. In other words, executes `make` without `-j` option. +Specify the profile for JerryScript (default: es5.1). In JerryScript all of the features are enabled by default, so an empty profile file turns on all of the available ECMA features. See also the related [README.md](https://github.com/jerryscript-project/jerryscript/blob/master/jerry-core/profiles/README.md). +E.g.: +**/home/iotjs/my-jerry-profile.profile** ``` -./tools/build.py --no-parallel-build +# Turn off every ES2015 feature EXCEPT the arrow functions +CONFIG_DISABLE_ES2015_BUILTIN +CONFIG_DISABLE_ES2015_PROMISE_BUILTIN +CONFIG_DISABLE_ES2015_TEMPLATE_STRINGS +CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN ``` --- -#### `--nuttx-home` -To build for nuttx os, nuttx home directory must be given. - ``` -./tools/build.py --target-os=nuttx --target-arch=arm --target-board=stm32f4dis --nuttx-home="..." +./tools/build.py --jerry-profile=/home/iotjs/my-jerry-profile.profile ``` --- -#### `--config` -Specify build configuration file path. +--- +#### `--js-backtrace` +Enable/disable backtrace information of JavaScript code (default: ON in debug and OFF in release build). ``` -./tools/build.py --config=build.arm.nuttx.stm32f4dis.config +./tools/build.py --js-backtrace ``` - -`build.default.config` file is in the source tree for default setting. - -If this option is not specified, `build.config` file will be applied. If the file is not exist, it will be copied from `build.default.config`. - -Parameters specified by the config file is applied, and then the parameters given by command line overwrite over the settings. - -If you need to apply the same set of parameters for each build, making your own config file and trigger build.py with the config file would be more convenient. \ No newline at end of file diff --git a/docs/build/Build-for-ARTIK.md b/docs/build/Build-for-ARTIK.md deleted file mode 100644 index 7b0729d7c0..0000000000 --- a/docs/build/Build-for-ARTIK.md +++ /dev/null @@ -1,38 +0,0 @@ -## Build IoT.js for ARTIK - -### Tizen on ARTIK10 cross-compile - -#### Prerequisites - -* ARTIK10 with Tizen (https://wiki.tizen.org/wiki/Tizen_On_ARTIK) -* Tizen Studio with Native app development CLI tools - - This is required to get rootstrap for Tizen (set of native libraries). -* arm-linux-gnueabi-gcc cross compiler (can be found in Tizen Studio / Native toolchain) - -#### Building -1. Make sure arm-linux-gnueabi-gcc is in path -2. Locate Tizen SDK. Default location is: ~/tizen-studio -3. In platforms/tizen-3.0/mobile there should be compatible rootstrap (eg. mobile-3.0-device) - -Compile: -``` bash -tools/build.py \ - --target-arch=arm --target-os=tizen --target-board=artik10 \ - --compile-flag="--sysroot=~/tizen-studio/platforms/tizen-3.0/mobile/rootstraps/mobile-3.0-device.core/" -``` - -#### Testing -Transfer iotjs binary and test file to the device: -``` bash -sdb push ./build/arm-tizen/debug/bin/iotjs /home/owner/iotjs/ -sdb push ./test/run_pass/test_console.js /home/owner/iotjs/ -``` - -Run the test: -``` bash -sdb shell -$ cd /home/owner/iotjs -$ ./iotjs test_console.js -``` - diff --git a/docs/build/Build-for-ARTIK053-TizenRT.md b/docs/build/Build-for-ARTIK053-TizenRT.md new file mode 100644 index 0000000000..bf0a0d7765 --- /dev/null +++ b/docs/build/Build-for-ARTIK053-TizenRT.md @@ -0,0 +1,139 @@ +### About + +This directory contains files to run IoT.js on [TizenRT](https://github.com/Samsung/TizenRT). + + +### How to build + +#### 1. Set up the build environment for Artik053 board + +##### Install toolchain + +Get the build in binaries and libraries, [gcc-arm-none-eabi-4_9-2015q3-20150921-linux.tar](https://launchpad.net/gcc-arm-embedded/4.9/4.9-2015-q3-update). + +Untar the gcc-arm-none-eabi-4_9-2015q3-20150921-linux.tar and export the path like + +``` +tar xvf gcc-arm-none-eabi-4_9-2015q3-20150921-linux.tar +export PATH=:$PATH + ``` + +##### Install genromfs to use romfs + +```bash +sudo apt-get install genromfs +``` + +##### Install kconfig-frontends to use menuconfig + +Refer to [Kconfig-frontends Installation](https://github.com/Samsung/TizenRT#appendix) + +##### Get IoT.js and TizenRT sources + +Clone IoT.js and TizenRT into iotjs-tizenrt directory + +```bash +mkdir iotjs-tizenrt +cd iotjs-tizenrt +git clone https://github.com/jerryscript-project/iotjs.git +git clone https://github.com/Samsung/TizenRT.git +``` + +The following directory structure is created after these commands +```bash +iotjs-tizenrt + + iotjs + + TizenRT +``` + +#### 2. Configure IoT.js + +This step is optional. You can edit the build config of IoT.js in `iotjs/build.config`. In order to enable modules you want, you can configure your own profile file, or you can add them as an option to the build command. For more details, please find the `ENABLE_MODULE_[NAME]` section in [How to write a new module](../devs/Writing-New-Module.md#enable_module_name). + +``` +ENABLE_MODULE_ADC +ENABLE_MODULE_GPIO +``` + +``` +$ ./tools/build.py --external-modules=./my-module --cmake-param=-DENABLE_MODULE_MYMODULE=ON +``` + +#### 3. Configure TizenRT + +```bash +cd TizenRT/os/tools +./configure.sh artik053/iotjs +cd .. +``` + +#### 4. Copy your app in ROMFS + +```bash +cp ../tools/fs/contents/ +# make ROMFS image +../tools/fs/mkromfsimg.sh +# The contents folder is later flashing into the target's /rom folder +``` + +NOTE: The romfs image file must not exceed 400kb. + +#### 5. Build IoT.js for TizenRT + +```bash +make IOTJS_ROOT_DIR=../../iotjs +``` + +If `IOTJS_ROOT_DIR` isn't given as the argument, IoT.JS codes, which are located in `external/iotjs` of TizenRT, will be used for the build. + +> :grey_exclamation: Trouble Shooting: Building IoT.js fails: You may encounter `arm-none-eabi-gcc: Command not found` error message while building IoT.js on a 64-bit system. This may be because the above toolchain you set uses 32-bit libs. For this matter, install the below toolchain as alternative. +> ``` +> $ sudo apt-get install -y libc6-i386 +> ``` + +#### 6. Flashing + +```bash +make download ALL +``` +> :grey_exclamation: Trouble Shooting: Flashing the binary via USB fails: Refer to [add-usb-device-rules](https://github.com/Samsung/TizenRT/blob/master/build/configs/artik053/README.md#add-usb-device-rules). Your `VendorID:ProductID` pair can be found in `lsusb` output as the below instance. +> +>``` +>$ lsusb +>Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub +>Bus 003 Device 005: ID 0403:6010 Future Technology Devices International, Ltd >FT2232C Dual USB-UART/FIFO IC +>``` + + +#### 7. Run IoT.js + +You should use `minicom` to login to the device: + +```bash +$ sudo minicom -s +``` +The following changes are necessaries in the `Serial port setup` menu: + +``` +Serial Device : /dev/ # e.g. /dev/ttyUSB0 +Hardware Flow Control : No +``` +After `Exit`, press an enter and the prompt should be available: + +```bash +TASH>> +``` +The following commands help to establish Internet connection on the device: + +```bash +TASH>> wifi startsta +TASH>> wifi join +TASH>> ifconfig wl1 dhcp +``` +Finally, the `iotjs` built-in command can be executed: + +```bash +TASH>> iotjs +Usage: iotjs [options] {FILE | FILE.js} [arguments] +TASH>> +``` diff --git a/docs/build/Build-for-NuttX.md b/docs/build/Build-for-NuttX.md deleted file mode 100644 index acc64868df..0000000000 --- a/docs/build/Build-for-NuttX.md +++ /dev/null @@ -1,134 +0,0 @@ -## Build IoT.js with NuttX - -### Target board -We work on STM32F4 board for NuttX and the detail of the reference board is well described at [STM32F4-discovery with BB](http://www.st.com/web/en/catalog/tools/FM116/SC959/SS1532/LN1199/PF255417). - -### Relation with STM board? -We do not have any business relation with STM board. It is selected because it has enough RAM and Flash ROM, so that development can be more comfortable. And it has lots of pins to play with. - -When IoT.js is built up and optimized, it may work in devices having smaller resource. - - -### 1. Prepare for prerequisite -#### Linux - -```bash -$ sudo apt-get install autoconf libtool gperf flex bison autoconf2.13 -$ sudo apt-get install cmake libncurses-dev libusb-1.0-0-dev -$ sudo apt-get install libsgutils2-dev gcc-arm-none-eabi minicom -``` - -To use menuconfig in NuttX, you may need to install kconfig frontend. - -```bash -$ git clone https://github.com/jameswalmsley/kconfig-frontends.git -$ cd kconfig-frontends -$ ./bootstrap -$ ./configure --enable-mconf -$ make -$ sudo make install -$ sudo ldconfig -``` - -#### macOS - -* Install Xcode from the app store and run once Xcode to install components. -* Install Xcode command line tools. -```bash -$ xcode-select --install -``` -* Install [Homebrew package manager](http://brew.sh/) -* Install packages -```bash -$ brew tap PX4/homebrew-px4 -$ brew update -$ brew install cmake bash-completion pkg-config kconfig-frontends -$ brew install gcc-arm-none-eabi libusb minicom -``` - -### 2. Build NuttX (For the first time) - -To generate headers which are required to build IoT.js, for the first time, you need to build NuttX at least once. This time NuttX build will be failed. But don't worry at this time. After one execution, you don't need this sequence any more. - -#### Supported NuttX version -|Repository|Tag Name| -|----------|:------:| -| nuttx | nuttx-7.19 | -| app | nuttx-7.19 | - -We only guarantee that the specified version will work well. It is recommended to check out with the specified tag from a git repository. - - -#### Follow the instruction -* [STM32F4-discovery](../targets/nuttx/stm32f4dis/README.md) - - -### 3. Build IoT.js for NuttX - -These options are needed. -```bash ---target-arch=arm ---target-os=nuttx ---nuttx-home=/path/to/nuttx ---target-board=stm32f4dis ---jerry-heaplimit=[..] -``` - -For example, -```bash -$ ./tools/build.py \ ---target-arch=arm --target-os=nuttx --nuttx-home=../nuttx \ ---target-board=stm32f4dis --jerry-heaplimit=78 -``` - -Library files will be generated like below when build is successful. - -```bash -$ ls build/arm-nuttx/release/lib -libhttpparser.a libiotjs.a libjerrycore.a libtuv.a -``` - -### 4. Build NuttX - -This time make command for NuttX has to be successful unlike above. - -#### Follow the instruction -* [STM32F4-discovery](../targets/nuttx/stm32f4dis/README.md) - -### 5. Run IoT.js - -#### USB Connection - -There are two USB Connections on the Target board. USB mini CN1 and USB micro CN5. Both USB ports need to be connected to your Host. CN1 is used for power and Flashing, but it will not appear as a device in Linux. CN5 is used for NSH and will appear as `/dev/ttyACM0(linux)` or `/dev/tty.usbmodem1(macOS)` when things work well. - -#### Use minicom - -```bash -// linux -$ minicom --device=/dev/ttyACM0 -// macOS -$ minicom --device=/dev/tty.usbmodem1 - -``` -You may need to enable _Add Carriage Return_ option. -* Press Ctrl-A + Z + U for short in minicom screen. (For linux user) -* Press [Meta](http://osxdaily.com/2013/02/01/use-option-as-meta-key-in-mac-os-x-terminal/) + Z for short in minicom screen. (For macOS user) - -Press _Enter_ key several times to trigger NuttShell to start. - -If micro SD is enabled, you can copy any script file to it and run with _nsh_, for example; -``` -NuttShell (NSH) -nsh> mount -t vfat /dev/mmcsd0 /mnt/sdcard -nsh> iotjs /mnt/sdcard/path_to_file.js -``` - -If you see -``` -+-----------------------------+ -| | -| Cannot open /dev/ttyACM0! | -| | -+-----------------------------+ -``` -and it stays on the screen, something is wrong. Blue LED may blink if NuttX is in abnormal state. Press black(reset) button on the board and try again. If you still see this warning message, begin with original NuttX code and check your board, USB line and other softwares. diff --git a/docs/build/Build-for-OpenWrt.md b/docs/build/Build-for-OpenWrt.md new file mode 100644 index 0000000000..52cd2160a2 --- /dev/null +++ b/docs/build/Build-for-OpenWrt.md @@ -0,0 +1,104 @@ +# IoT.js for OpenWrt build guide + +> :exclamation: This document describes an experimental feature and considerations. +Please be aware that every experimental feature may change, be broken, +or be removed in the future without any notice. + + +The document presents the steps required to compile the IoT.js +for OpenWrt. For target device, the TP-Link WR1043ND v1.x router is +used. Please be advised, that if you have a different one, minor +modifications to this document could be required. + + +IMPORTANT! + +As the TP-Link WR1043ND is a mips based device and mips is a big-endian +architecture. A JerryScipt snapshot which was built on an little-endian +system will not work correctly. Thus the IoT.js must be +built with disabled snaphost mode. + +## OpenWrt notes + +Since January 2018 the OpenWrt and LEDE project have merged into one +and thus the old OpenWrt parts are now usable only from +an archived repository: https://github.com/openwrt/archive + +## OpenWrt toolchain setup + +To build the IoT.js for OpenWrt, a toolchain is required for +the target router/device. The toolchain setup in this document was +tested on an Ubuntu 16.04.3 LTS Linux. + +Steps required for toolchain creation: + +### 0. Install OpenWrt build requirements +```sh +$ sudo apt-get install git-core build-essential libssl-dev libncurses5-dev unzip gawk zlib1g-dev subversion mercurial +``` + +### 1. Clone OpenWrt (Chaos Calmer version) + +```sh +$ git clone https://github.com/openwrt/archive openwrt -b chaos_calmer +$ cd openwrt +``` + +### 2. Run Menuconfig and configure the OpenWrt + +```sh +$ make menuconfig +``` + +Options which should be set: +* Set "Target System" to "Atheros AR7xxx/AR9xxx". +* Set "Target Profile" to "TP-LINK TL-WR1043N/ND". + +Save the configuration (as .config) and exit from the menuconfig. + +### 3. Configure the environment variables + +```sh +$ export BUILDROOT=$(pwd) # where the openwrt root dir is +$ export STAGING_DIR=${BUILDROOT}/staging_dir/ # required by the compiler +$ export PATH=$PATH:${STAGING_DIR}/host/bin:${STAGING_DIR}/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin/ +``` + +The name `toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2` is created based on the menuconfig. +This changes depending on the target device! + +### 4. Build the OpenWrt + +```sh +$ make +``` + +### 5. Check if the compiler was built + +```sh +$ mips-openwrt-linux-gcc --version # running this should print out the version information +``` + +At this point we have the required compiler for OpenWrt. + + +## Build IoT.js for OpenWrt + +### 0. Check environment + +Please check if the `STAGING_DIR` is configured correctly and that the toolchain binary is on the `PATH`. + +### 1. Run the build with the OpenWrt toolchain file + +```sh +$ ./tools/build.py --experimental --target-os openwrt --target-arch mips --no-snapshot --buildtype=release +``` + +It is advised to use release build as it is smaller than the debug build and can fit on the +target router device. + +### 2. Copy the binary + +After a successful build, the `build/mips-openwrt/release/bin/iotjs` +binary file can be copied to the target device. +On how to copy a binary file to an OpenWrt target device, please see the OpenWrt manual(s). diff --git a/docs/build/Build-for-RPi2.md b/docs/build/Build-for-RPi2-Linux.md similarity index 75% rename from docs/build/Build-for-RPi2.md rename to docs/build/Build-for-RPi2-Linux.md index c1a52d53d8..3a477572f7 100644 --- a/docs/build/Build-for-RPi2.md +++ b/docs/build/Build-for-RPi2-Linux.md @@ -1,4 +1,3 @@ -## Build IoT.js with Raspberry Pi 2 IoT.js supports two build types: @@ -7,7 +6,12 @@ IoT.js supports two build types: ### Setting Raspberry Pi -IoT.js officially supports Raspbian. For more information, please visit [the official site](https://www.raspberrypi.org/downloads/raspbian/). +IoT.js officially supports Raspbian. +This setting guide is based on the image below. + +|Raspbian Image | +|----------| +| [2017-11-29-raspbian](http://downloads.raspberrypi.org/raspbian/images/raspbian-2017-12-01/) | #### Enable the I2C interface @@ -18,8 +22,8 @@ From the command line type: sudo raspi-config ``` This will launch raspi-config utility. - * Select "9 Advanced Options" - * Select "A6 I2C" + * Select "5 Interfacing Options" + * Select "P5 I2C" The screen will ask you to enable I2C interface. * Select "Yes" @@ -57,10 +61,20 @@ For more information about overlays, refer to [README](https://github.com/raspbe To use UART module, the UART interface must be enabled. -In `/boot/config.txt` file, change the value of enable_uart from 0 to 1. -``` -enable_uart=1 +From the command line type: +```bash +sudo raspi-config ``` +This will launch raspi-config utility. + * Select "5 Interfacing Options" + * Select "P6 Serial" + +The screen will ask you to enable Serial interface. + * Select "Yes" + * Select "Ok" + * Select "Finish" to return to the command line. + +Reboot your Raspberry Pi. To disable the serial console, edit the file `/boot/cmdline.txt`. remove the word phase ```"console=serial0,115200"``` or ```"console=ttyAMA0,115200"``` @@ -72,6 +86,25 @@ Reboot your Raspberry Pi. * Note for Raspberry Pi 3 : You should use /dev/ttyS0 instead of /dev/ttyAMA0 in RPI3. +#### Enable the SPI interface + +To use SPI module, the SPI interface must be enabled. + +From the command line type: +```bash +sudo raspi-config +``` +This will launch raspi-config utility. + * Select "5 Interfacing Options" + * Select "P4 SPI" + +The screen will ask you to enable SPI interface. + * Select "Yes" + * Select "Ok" + * Select "Finish" to return to the command line. + +Reboot your Raspberry Pi. + ### Build IoT.js on your desktop. #### Prerequisite @@ -111,7 +144,7 @@ Give `target-arch`, `target-os` and `target-board` options to the script named ' #### Running in Raspberry Pi 2 -This script gives you `build/arm-linux/release/iotjs/iotjs` or `build/arm-linux/debug/iotjs/iotjs`. +This script gives you `build/arm-linux/release/bin/iotjs` or `build/arm-linux/debug/bin/iotjs`. Copy this binary with your favorite tool or `scp` like below. ``` bash diff --git a/docs/build/Build-for-RPi3-Tizen.md b/docs/build/Build-for-RPi3-Tizen.md new file mode 100644 index 0000000000..f85fda65c1 --- /dev/null +++ b/docs/build/Build-for-RPi3-Tizen.md @@ -0,0 +1,127 @@ + +### 1. Tizen on RPi3 GBS build + +#### Prerequisites + +* Install SDB tool (https://developer.tizen.org/development/tizen-studio/download) + + It is required to send file to target, which is in Tizen Studio. + +* Modify sources.list of Ubuntu + + It is a buil system to create Tizen RPM package. + To install gbs in your system, it's required to add the Tizen tools repository to the source list + ``` + $ sudo vim /etc/apt/sources.list + ``` + + In Ubuntu 16.04, append the following line to the source list: + ``` bash + deb [trusted=yes] http://download.tizen.org/tools/latest-release/Ubuntu_16.04/ / + ``` + + In Ubuntu 14.04, append the follwing line to the source list: + ``` bash + deb http://download.tizen.org/tools/latest-release/Ubuntu_14.04/ / + ``` + +* Install GBS + + ``` bash + sudo apt-get update + sudo apt-get install gbs + ``` + +* Prepare a GBS configuration file. + + You can use sample gbs configuration in config/tizen/sample.gbs.conf. + + See https://source.tizen.org/documentation/reference/git-build-system/configuration-file for details. + + +#### Building +* You can modify IoT.js build option on the spec file. +(config/tizen/packaging/iotjs.spec) + +* Run gbsbuild.sh at first. +Compile: +``` bash +./config/tizen/gbsbuild.sh +``` + +The following options are provided. +``` +--debug: Build output is 'debug'. If this option is not specified, it is 'release'. +--clean: Make a clean gbs build by deleting the old build root. +``` + +### 2. Bring up RPi3 with Tizen +Please see the following guide to bring up your RPI3 target with Tizen. +You can refer "Raspberry Pi 3" section of command-line-flash part. + +https://developer.tizen.org/development/iot-preview/getting-started/flashing-tizen-images#command-line-flash + +#### Setting up serial port + Please refer the tizen wiki https://wiki.tizen.org/Raspberry_Pi#Debugging + + + +#### Setting up IP + +You can set up IP using WiFi or Ethernet + +* Setup IP on RPi3 target using WiFi: + + https://developer.tizen.org/development/iot-preview/getting-started/flashing-tizen-images#wifi-setup + + +* Setup IP on RPi3 target using ethernet +``` bash + User id/passwd : root / tizen + (target)$ ifconfig eth0 down + (target)$ ifconfig eth0 192.168.1.11 netmask 255.255.255.0 up + (target)$ route add default gw 192.168.1.1 +``` + + If you want to use your fixed ip when you reboot, add ip settings in /etc/profile. + + Please make sure to run before modifying /etc/profile. +``` +(target) $ mount -o remount,rw / +``` +``` bash + (ubuntu)$ sdb pull /etc/profile + (ubuntu)$ vi profile + + Adding the following configurations + ifconfig eth0 down + ifconfig eth0 192.168.1.11 netmask 255.255.255.0 up + route add default gw 192.168.1.1 + + (ubuntu)$ sdb push profile /etc/ +``` + +#### SDB connection + Now you can connect RPi3 on Ubuntu PC + +``` bash +(ubuntu)$ sdb connect 192.168.1.11 + ``` + +#### Install +Transfer iotjs binary and test file to the device: +``` bash +(ubuntu)$ sdb push ~/GBS-ROOT/local/repos/tizen_unified_m1/armv7l/RPMS/iotjs-1.0.0-0.armv7l.rpm /tmp +(ubuntu)$ sdb push ./test/run_pass/test_console.js /home/owner/iotjs/ +(ubuntu)$ sdb root on +(ubuntu)$ sdb shell +(target)$ cd /tmp +(only in headless Tizen 4.0 target)$ mount -o remount,rw / +(target)$ rpm -ivh --force iotjs-1.0.0-0.armv7l.rpm +``` + +#### Run the test: +``` bash +(ubuntu)$ sdb shell +(target)$ iotjs test_console.js +``` diff --git a/docs/build/Build-for-STM32F4-NuttX.md b/docs/build/Build-for-STM32F4-NuttX.md new file mode 100644 index 0000000000..6add8d86c0 --- /dev/null +++ b/docs/build/Build-for-STM32F4-NuttX.md @@ -0,0 +1,395 @@ + +### Target board +We work on STM32F4 board for NuttX and the detail of the reference board is well described at [STM32F4-discovery with BB](http://www.st.com/web/en/catalog/tools/FM116/SC959/SS1532/LN1199/PF255417). + +### Relation with STM board? +We do not have any business relation with STM board. It is selected because it has enough RAM and Flash ROM, so that development can be more comfortable. And it has lots of pins to play with. + +When IoT.js is built up and optimized, it may work in devices having smaller resource. + + +### 1. Prepare for prerequisite + +#### Linux + +```bash +$ sudo apt-get install autoconf libtool gperf flex bison autoconf2.13 +$ sudo apt-get install cmake libncurses-dev libusb-1.0-0-dev +$ sudo apt-get install libsgutils2-dev gcc-arm-none-eabi minicom +``` + +To use menuconfig in NuttX, you may need to install kconfig frontend. + +```bash +$ git clone https://github.com/jameswalmsley/kconfig-frontends.git +$ cd kconfig-frontends +$ ./bootstrap +$ ./configure --enable-mconf +$ make +$ sudo make install +$ sudo ldconfig +``` + +#### macOS + +* Install Xcode from the app store and run once Xcode to install components. +* Install Xcode command line tools. +```bash +$ xcode-select --install +``` +* Install [Homebrew package manager](http://brew.sh/) +* Install packages +```bash +$ brew tap PX4/homebrew-px4 +$ brew update +$ brew install cmake bash-completion pkg-config kconfig-frontends +$ brew install gcc-arm-none-eabi libusb minicom +``` + + +### 2. Set up the build environment for STM32F4-Discovery board + +#### Supported Nuttx version +|Repository|Tag Name| +|----------|:------:| +| nuttx | nuttx-7.25 | +| app | nuttx-7.25 | + +We only guarantee that the specified version will work well. It is recommended to check out with the specified tag from a git repository. + +#### Clone repository + +Clone IoT.js and NuttX into iotjs-nuttx directory + +```bash +$ mkdir iotjs-nuttx +$ cd iotjs-nuttx +$ git clone https://github.com/jerryscript-project/iotjs.git +$ git clone https://bitbucket.org/nuttx/nuttx.git --branch nuttx-7.25 +$ git clone https://bitbucket.org/nuttx/apps.git --branch nuttx-7.25 +$ git clone https://github.com/texane/stlink.git +``` + +Note that we only support the specified git tag from nuttx repository + +The following directory structure is created after these commands + +```bash +iotjs-nuttx + + apps + + iotjs + | + config + | + nuttx + | + stm32f4dis + + nuttx + + stlink +``` + + +### 3. Build NuttX (For the first time) + +To generate headers which are required to build IoT.js, for the first time, you need to build NuttX at least once. This time NuttX build will be failed. But don't worry at this time. After one execution, you don't need this sequence any more. + +#### Add IoT.js as a builtin application for NuttX + +```bash +$ cd apps/system +$ mkdir iotjs +$ cp ../../iotjs/config/nuttx/stm32f4dis/app/* ./iotjs/ +``` + +#### Configure NuttX + +```bash +# assuming you are in iotjs-nuttx folder +$ cd nuttx/tools + +# configure NuttX USB console shell +$ ./configure.sh stm32f4discovery/usbnsh +``` + +Now you can configure nuttx like either of below. For convenience, we provide built-in configure file for you. (This configure file is equipped with modules specified as `always`. For `optional` modules, you might follow instructions below.) +```bash +$ cd .. +$ cp ../iotjs/config/nuttx/stm32f4dis/config.default .config +``` + +Or if you want to configure yourself, you can follow guide below. +```bash +$ cd .. +# might require to run "make menuconfig" twice +$ make menuconfig +``` + +Followings are the options to set: + +* Common + * Change `Build Setup -> Build Host Platform` from _Windows_ to [_Linux_|_OSX_] + * Enable `System Type -> FPU support` + * Enable `System Type -> STM32 Peripheral Support -> SDIO` + * Enable `RTOS Features -> Clocks and Timers -> Support CLOCK_MONOTONIC` + * Enable `RTOS Features -> Pthread Options -> Enable mutex types` + * Enable `RTOS Features -> Files and I/O -> Enable /dev/console` + * Enable `RTOS Features -> Work queue support -> High priority (kernel) worker thread` + * Disable `Device Drivers -> Disable driver poll interfaces` + * Enable `Device Drivers -> MMC/SD Driver Support` + * Enable `Device Drivers -> MMC/SD Driver Support -> MMC/SD SDIO transfer support` + * Enable `Networking Support -> Networking Support` + * Enable `Networking Support -> Socket Support -> Socket options` + * Enable `Networking Support -> Unix Domain Socket Support` + * Enable `Networking Support -> TCP/IP Networking` + * Enable `Networking Support -> TCP/IP Networking -> Enable TCP/IP write buffering` + * Enable `File Systems -> FAT file system` + * Enable `File Systems -> FAT file system -> FAT upper/lower names` + * Enable `File Systems -> FAT file system -> FAT long file names` + * Enable `Device Drivers -> Network Device/PHY Support -> Late driver initialization` + * Enable `Library Routines -> Standard Math library` + * Enable `Application Configuration -> System Libraries and NSH Add-ons -> IoT.js` + * Enable all children of `Application Configuration -> System Libraries and NSH Add-ons -> readline() Support` (for those who wants to use readline) + +* For `net` module + * Enable `System Type -> STM32 Peripheral Support -> Ethernet MAC` + * Disable `System Type -> STM32 Peripheral Support -> USART2` + * Enable `System Type -> STM32 Peripheral Support -> USART6` + * Set `System Type -> Ethernet MAC configuration -> PHY address` to `0` + * Set `System Type -> Ethernet MAC configuration -> PHY Status Register Address (decimal)` to `31` + * Enable `System Type -> Ethernet MAC configuration -> PHY Status Alternate Bit Layout` + * Set `System Type -> Ethernet MAC configuration -> PHY Mode Mask` to `0x001c` + * Set `System Type -> Ethernet MAC configuration -> 10MBase-T Half Duplex Value` to `0x0004` + * Set `System Type -> Ethernet MAC configuration -> 100Base-T Half Duplex Value` to `0x0008` + * Set `System Type -> Ethernet MAC configuration -> 10Base-T Full Duplex Value` to `0x0014` + * Set `System Type -> Ethernet MAC configuration -> 10MBase-T Full Duplex Value` to `0x0018` + * Set `System Type -> Ethernet MAC configuration -> RMII clock configuration` to `External RMII clock` + * Enable `Board Selection -> STM32F4DIS-BB base board` + * Set `Device Drivers -> Network Device/PHY Support -> Board PHY Selection` to `SMSC LAN8720 PHY` + * Enable `Networking Support -> Data link support -> Local loopback` + * Enable `Networking Support -> TCP/IP Networking -> TCP/IP backlog support` + * Enable `Networking Support -> ARP Configuration -> ARP send` + +* For `dgram` + * Enable `Networking Support > UDP Networking` + +* For `pwm` module + * Enable `System Type -> STM32 Peripheral Support -> TIM(N)` + * Enable `System Type -> Timer Configuration -> TIM(N) PWM` + * Set `System Type -> Timer Configuration -> TIM(N) PWM -> TIM(n) PWM Output Channel` to channel number you want + * Enable `Device Drivers -> PWM Driver Support` + +* For `adc` module + * Enable `System Type -> STM32 Peripheral Support -> ADC(N)` + * Enable `System Type -> STM32 Peripheral Support -> TIM(M)` + * Enable `System Type -> Timer Configuration -> TIM(M) ADC` + * Enable `Device Drivers -> Analog Device(ADC/DAC) Support` + * Enable `Device Drivers -> Analog Device(ADC/DAC) Support -> Analog-to-Digital Conversion` + +* For `uart` module + * Enable `System Type -> STM32 Peripheral Support -> U[S]ART(N)` + +* For `i2c` module + * Enable `System Type -> STM32 Peripheral Support -> I2C1` + * Enable `Device Drivers -> I2C Driver Support` + +* For `spi` module + * Enable `System Type -> STM32 Peripheral Support -> SPI1` + * Enable `Device Drivers -> SPI exchange` + +#### Build NuttX Context + +```bash +# assuming you are in iotjs-nuttx folder +$ cd nuttx/ +$ make context +``` + + +### 4. Build IoT.js for NuttX + +These options are needed. +```bash +--target-arch=arm +--target-os=nuttx +--nuttx-home=/path/to/nuttx +--target-board=stm32f4dis +--jerry-heaplimit=[..] +``` + +For example, +```bash +$ ./tools/build.py \ +--target-arch=arm --target-os=nuttx --nuttx-home=../nuttx \ +--target-board=stm32f4dis --jerry-heaplimit=78 +``` + +Library files will be generated like below when build is successful. + +```bash +$ ls build/arm-nuttx/release/lib +libhttpparser.a libiotjs.a libjerrycore.a libtuv.a +``` + +### 5. Build NuttX + +```bash +# assuming you are in iotjs-nuttx folder +$ cd nuttx/ +$ make IOTJS_ROOT_DIR=../iotjs +``` +For release version, you can type R=1 make on the command shell. + + +### 6. Flashing + +Connect Mini-USB for power supply and connect Micro-USB for `NSH` console. + +To configure `stlink` utility for flashing, follow the instructions [here](https://github.com/texane/stlink#build-from-sources). + +To install, +```bash +# assuming you are in stlink folder +$ cd stlink +$ make +``` + +To flash, +```bash +# assuming you are in nuttx folder +$ sudo ../stlink/build/Release/st-flash write nuttx.bin 0x8000000 +``` + + +### 7. Run IoT.js + +#### USB Connection + +There are two USB Connections on the Target board. USB mini CN1 and USB micro CN5. Both USB ports need to be connected to your Host. CN1 is used for power and Flashing, but it will not appear as a device in Linux. CN5 is used for NSH and will appear as `/dev/ttyACM0(linux)` or `/dev/tty.usbmodem1(macOS)` when things work well. + +#### Use minicom + +```bash +// linux +$ minicom --device=/dev/ttyACM0 +// macOS +$ minicom --device=/dev/tty.usbmodem1 + +``` +You may need to enable _Add Carriage Return_ option. +* Press Ctrl-A + Z + U for short in minicom screen. (For linux user) +* Press [Meta](http://osxdaily.com/2013/02/01/use-option-as-meta-key-in-mac-os-x-terminal/) + Z for short in minicom screen. (For macOS user) + +Press _Enter_ key several times to trigger NuttShell to start. + +If micro SD is enabled, you can copy any script file to it and run with _nsh_, for example; +``` +NuttShell (NSH) +nsh> mount -t vfat /dev/mmcsd0 /mnt/sdcard +nsh> iotjs /mnt/sdcard/path_to_file.js +``` + +If you see +``` ++-----------------------------+ +| | +| Cannot open /dev/ttyACM0! | +| | ++-----------------------------+ +``` +and it stays on the screen, something is wrong. Blue LED may blink if NuttX is in abnormal state. Press black(reset) button on the board and try again. If you still see this warning message, begin with original NuttX code and check your board, USB line and other softwares. + + +## EXTRA STM32 SUPPORT + +While STM32F4-Discovery is the reference target, +IoT.js can be built for other based STM32 boards: + +* [Nucleo-F767zi](https://www.st.com/en/evaluation-tools/nucleo-f767zi.html) + +The procedure is similar to STM32F4, so only specific info will be explained in following chapters: + +## NUCLEO-F767ZI + +### 1. Prepare for prerequisite + +See general instructions for STM32F4 in related chapter. + +### 2. Set up the build environment for STM32F7-Nucleo board + +#### Supported Nuttx version for NUCLEO-F767ZI + +Since development is still in progress, master branch of NuttX will be used +until a version is released with relevant STM32F7 support. + +#### Clone repository for NUCLEO-F767ZI + +Clone IoT.js and NuttX into iotjs-nuttx directory: + +```bash +$ mkdir iotjs-nuttx +$ cd iotjs-nuttx +$ git clone https://github.com/jerryscript-project/iotjs.git +$ git clone https://bitbucket.org/nuttx/nuttx.git --branch master +$ git clone https://bitbucket.org/nuttx/apps.git --branch master +``` +### 3. Build NuttX (For the first time) for NUCLEO-F767ZI + +See general instructions for STM32F4 in related chapter. + +#### Add IoT.js as a builtin application for NuttX for NUCLEO-F767ZI + +See general instructions for STM32F4 in related chapter. + +##### Configure NuttX for NUCLEO-F767ZI + +See general instructions for STM32F4 in related chapter. but instead of configuring for discovery in STM32F4: + +```bash +$ ./configure.sh stm32f4discovery/usbnsh +``` + +Nucleo-144 board configuration will be needed with STM32F7 MCU (with Network Controller support): + +```bash +$ ./configure.sh nucleo-144/f767-netnsh +``` + +Now you can configure nuttx like either of below. For convenience, we provide built-in configure file for you. (This configure file is equipped with modules specified as `always`. For `optional` modules, you might follow instructions below.) +```bash +$ cd .. +$ cp ../iotjs/config/nuttx/stm32f7nucleo/config.default .config +``` + +### 4. Build IoT.js for NuttX for NUCLEO-F767ZI + + +These options are needed. +```bash +--target-arch=arm +--target-os=nuttx +--nuttx-home=/path/to/nuttx +--target-board=stm32f7nucleo +--jerry-heaplimit=[..] +``` + +For example, +```bash +$ ./tools/build.py \ +--target-arch=arm --target-os=nuttx --nuttx-home=../nuttx \ +--target-board=stm32f7nucleo --jerry-heaplimit=78 +``` +Library files will be generated like below when build is successful, at least expect to find: + +```bash +$ ls build/arm-nuttx/*/lib +libhttpparser.a libiotjs.a libjerrycore.a libtuv.a +``` + +### 5. Build NuttX for NUCLEO-F767ZI + +See general instructions for STM32F4 in related chapter. + +### 6. Flashing for NUCLEO-F767ZI + +See general instructions for STM32F4 in related chapter. + +### 7. Run IoT.js for NUCLEO-F767ZI + +See general instructions for STM32F4 in related chapter. diff --git a/docs/build/Build-for-Windows.md b/docs/build/Build-for-Windows.md new file mode 100644 index 0000000000..7ac87357c2 --- /dev/null +++ b/docs/build/Build-for-Windows.md @@ -0,0 +1,70 @@ +# IoT.js for Windows build guide + +> :exclamation: This document describes an experimental feature and considerations. +Please be aware that every experimental feature may change, be broken, +or be removed in the future without any notice. + + +The document presents the steps required to compile the IoT.js +for Windows. +Tested on Windows 10 and with Visual Studio 2017 Community Edition. + +## Build IoT.js for Windows + +### 0. Check environment + +Check if the following tools are installed: + * GIT + * Visual Studio 2017 with C++ support + * Python 3 + * CMake + +Additionally clone the IoT.js repository into a convenient directory. +In the document the `C:\dev\iotjs` path will be used as an example. + +### 1. Run the build script + +To create the required Visual Studio solution file(s) the build scripts needs to be +executed. Please start a Command Prompt and navigate to the source directory where +the IoT.js is cloned. + +In the IoT.js directory issue the following command: + +```sh +C:\dev\iotjs> .\tools\build.py --experimental +``` + +Currently for Windows the `--experimental` option is a must. Additionally if +other options are required it can be specified after this option. + +This command will create the solution files in the build directory. +Specifically in the `build\i686-windows\debug` directory in case of debug build. +In case of release build the solution files will be in the `build\i686-windows\release\` +directory. + +Please note that currently only the `i686` target is supported. + +### 2. Open the IoT.js solution file + +In the `build\i686-windows\debug` directory the `IOTJS.sln` file should be opened +with Visual Studion 2017. + +### 3. Build + +After the IoT.js solution file is opened the Visual Studio can now start the build. +Press CTRL+SHIFT+B to build the whole solution. + +The resulting iotjs.exe will be placed in the build's `bin\Debug` or `bin\Release` +directory depending on the configuration chosen in the Visual Studio. + +### Extra + +On Windows the test runner can also be executed. To do this the following steps are required: + +1. Have a built iotjs.exe +2. Start a command prompt +3. Navigate to the IoT.js source directory +4. Execute the test runner. Ex.: +```sh +C:\dev\iotjs> tools\testrunner.py build\i686-windows\debug\bin\Debug\iotjs.exe +``` diff --git a/docs/build/Build-for-Linux.md b/docs/build/Build-for-x86-Linux.md similarity index 84% rename from docs/build/Build-for-Linux.md rename to docs/build/Build-for-x86-Linux.md index c047a226a1..7af9032eba 100644 --- a/docs/build/Build-for-Linux.md +++ b/docs/build/Build-for-x86-Linux.md @@ -7,7 +7,7 @@ *** #### Build Host -Ubuntu 14.04 is recommended. Other Unix like platforms can be used. If it doesn't seem to work properly on other platforms, please look into the [Issues](https://github.com/Samsung/iotjs/issues) page. Someone may have already tried. If you can't find any related one, please leave an issue for help. +Ubuntu 14.04 is recommended. Other Unix like platforms can be used. If it doesn't seem to work properly on other platforms, please look into the [Issues](https://github.com/jerryscript-project/iotjs/issues) page. Someone may have already tried. If you can't find any related one, please leave an issue for help. #### Directory structure @@ -41,7 +41,7 @@ Clone our repository to look around and test it. If it attracts you and you want To get the source for this repository, ``` cd harmony -git clone https://github.com/Samsung/iotjs.git +git clone https://github.com/jerryscript-project/iotjs.git cd iotjs ``` @@ -67,6 +67,7 @@ buildtype=debug|release (debug is default) builddir=build (build is default) clean buildlib (default is False) +profile=path-to-profile (default: profiles/default.profile) target-arch=x86|x86_64|x64|i686|arm (depends on your host platform) target-os=linux|nuttx|darwin|osx (linux is default) target-board @@ -74,10 +75,7 @@ cmake-param compile-flag link_flag external-include-dir -external-static-lib -external-shared-lib -iotjs-include-module -iotjs-exclude-module +external-lib jerry-cmake-param jerry-compile-flag jerry-link-flag @@ -87,10 +85,10 @@ jerry-heaplimit (default is 81, may change) jerry-memstat (default is False) no-init-submodule (default is init) no-check-tidy (default is check) -no-check-test (default is check) no-parallel-build no-snapshot nuttx-home= (no default value) +run-test (default is False) ``` To give options, please use two dashes '--' before the option name as described in the following sections. @@ -101,8 +99,8 @@ Options that may need explanations. * jerry-heaplimit: JerryScript default heap size (as of today) is 256Kbytes. This option is to change the size for embedded systems, NuttX for now, and current default is 81KB. For linux, this has no effect. While building nuttx if you see an error `region sram overflowed by xxxx bytes`, you may have to decrease about that amount. * jerry-memstat: turn on the flag so that jerry dumps byte codes and literals and memory usage while parsing and execution. * no-check-tidy: no checks codes are tidy. we recommend to check tidy. -* no-check-test: do not run all tests in test folder after build. * nuttx-home: it's NuttX platform specific, to tell where the NuttX configuration and header files are. +* run-test: run all tests in test folder after build. If you want to know more details about options, please check the [Build Script](Build-Script.md) page. @@ -110,13 +108,24 @@ If you want to know more details about options, please check the [Build Script]( #### Include extended module There are two ways to include [extended module](../api/IoT.js-API-reference.md). -The first way is to modify a property value of module in `build.config` file. You can move a module name from 'exclude' to 'include'. +The first way is to specify the `ENABLE_MODULE_[NAME]=ON` CMake parameter, where `[NAME]` is the uppercase name of the module. + +``` +./tools/build.py --cmake-param=-DENABLE_MODULE_DGRAM=ON +``` + +The second way is by using profile descriptors, where a profile file contains the list of enabled modules. E.g.: + +**my-profile** +``` +ENABLE_MODULE_IOTJS_CORE_MODULES +ENABLE_MODULE_IOTJS_BASIC_MODULES +ENABLE_MODULE_DGRAM +``` -The second way is by using build options which is `--iotjs-include-module`. -If you enter several modules, separate them with a comma. ``` -./tools/build.py --iotjs-include-module=dgram,pin,gpio +./tools/build.py --profile=./my-profile ``` @@ -163,7 +172,7 @@ Executable name is **'iotjs'** and resides in (target-arch)-(target-os)/(buildty To run greetings JavaScript in test folder, for example; ``` -./build/x86_64-linux/debug/iotjs/iotjs ./test/run_pass/test_console.js +./build/x86_64-linux/debug/bin/iotjs ./test/run_pass/test_console.js ``` #### Set execution Options @@ -187,12 +196,12 @@ To print memory statistics, follow the below steps; ``` ./tools/build.py --jerry-memstat -./build/x86_64-linux/debug/iotjs/iotjs --memstat ./test/run_pass/test_console.js +./build/x86_64-linux/debug/bin/iotjs --mem-stats ./test/run_pass/test_console.js ``` With given `show-opcodes` option, opcodes will be shown. ``` -./build/x86_64-linux/debug/iotjs/iotjs --show-opcodes ./test/run_pass/test_console.js +./build/x86_64-linux/debug/bin/iotjs --show-opcodes ./test/run_pass/test_console.js ``` ### 4. Clean build directory diff --git a/docs/help/Assigned-people.md b/docs/contributing/Assigned-People.md similarity index 72% rename from docs/help/Assigned-people.md rename to docs/contributing/Assigned-People.md index 60a9a9857d..bb683d94f1 100644 --- a/docs/help/Assigned-people.md +++ b/docs/contributing/Assigned-People.md @@ -1,11 +1,13 @@ #### Maintainers -* akiss77 (integration) +* akosthekiss (integration) * LaszloLango (integration) * zherczeg (Steering Committee) * yichoi (Steering Committee, Project main contact) #### Committers * chokobole -* nova0821 * glistening -* hs0225 \ No newline at end of file +* hs0225 +* daeyeon +* bzsolt +* galpeter \ No newline at end of file diff --git a/docs/help/Community-Guidelines.md b/docs/contributing/Community-Guidelines.md similarity index 96% rename from docs/help/Community-Guidelines.md rename to docs/contributing/Community-Guidelines.md index 9789400fd3..934a182010 100644 --- a/docs/help/Community-Guidelines.md +++ b/docs/contributing/Community-Guidelines.md @@ -7,7 +7,7 @@ Community participants must adhere to these simple rules:
-### Community Consensus, Lazy Consensus and Slient Consent +### Community Consensus, Lazy Consensus and Silent Consent Community consensus about a Project issue means that the issue has been submitted to and discussed by Contributors, and that ALL discussing member agree about the issue.

Lazy consensus means that Contributors may proceed with work when they have reason to believe that other Contributors in the community will agree with the direction of their work, and do not need to stop or initiate unnecessary discussion about the work. Contributors should publish their work (that is, merge proposals to master branch) in a timely manner to allow others to possibly raise issues about the work. When the Contributor is not sure there will be consensus, they should raise a proposal to the community via appropriate public communication channels(**_currently Github issues is possible way to achieve this_**)

diff --git a/docs/help/Governance.md b/docs/contributing/Governance.md similarity index 100% rename from docs/help/Governance.md rename to docs/contributing/Governance.md diff --git a/docs/help/Patch-Submission-Process.md b/docs/contributing/Patch-Submission-Process.md similarity index 97% rename from docs/help/Patch-Submission-Process.md rename to docs/contributing/Patch-Submission-Process.md index a6ad0c4341..175e63a408 100644 --- a/docs/help/Patch-Submission-Process.md +++ b/docs/contributing/Patch-Submission-Process.md @@ -12,7 +12,7 @@ Smaller patches are generally easier to understand and test, so please submit ch The sign-off is a simple line at the end of the explanation for the patch, which certifies that you wrote it or otherwise have the right to pass it on as an Open Source patch. The sign-off is required for a patch to be accepted. -#### 3. Open [a Github pull request](https://github.com/Samsung/iotjs/pulls) +#### 3. Open [a Github pull request](https://github.com/jerryscript-project/iotjs/pulls) #### 4. What if my patch is rejected? @@ -37,4 +37,4 @@ Changes should be reviewed in reasonable amount of time. Maintainers and Committ Connect your local repository to the original upstream repository by adding it as a remote. Pull in upstream changes often to stay up-to-date so that when you submit your pull request, merge conflicts will be less likely. * For more details, see [GitHub fork synching guidelines](https://help.github.com/articles/syncing-a-fork/). -[Create a branch](https://guides.github.com/introduction/flow/) for your edits. \ No newline at end of file +[Create a branch](https://guides.github.com/introduction/flow/) for your edits. diff --git a/docs/devs/API-Document-Guidelines.md b/docs/devs/API-Document-Guidelines.md new file mode 100644 index 0000000000..e87239fc73 --- /dev/null +++ b/docs/devs/API-Document-Guidelines.md @@ -0,0 +1,223 @@ +## This is a sample API reference. Please use this as a guideline to write your module's API references. + +- If you have any questions about this guide, please let us know as an issue. +- `Markdown Example` is added to help understanding, and you can ignore it when writing the actual document. +- The document contents should be in order of `"Module"`, `"Module Function"`, `"Class"`, `"Constructor"`, `"Properties"`, `"Static Function"`, `"Prototype Functions"`, and `"Events"`. If the content does not exist, it can be omitted. +- `Module Functions` are what you can directly invoke without an instance of a certain Class. E.g) net.connect. +- In case of `experimental` module, it's required to explicitly indicate that the features are experimental. Please put the caution below to the beginning of the document. +> :exclamation: This document describes an experimental feature and considerations. Please be aware that every experimental feature may change, be broken, or be removed in the future without any notice. + +*** + +### Platform Support + +The following shows `{Your_module_name}` module APIs available for each platform. + +| | Linux
(Ubuntu) | Tizen
(Raspberry Pi) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | TizenRT
(Artik053) | +| :---: | :---: | :---: | :---: | :---: | :---: | +| {class_name}.{functionName1} | O | O | O | O | O | +| {class_name}.{functionName2} | O | O | O | O | O | +| {class_name}.{functionName3} | O | O | O | O | O | + +# {Your_module_name} + +- Write a brief description of this module here. +- The first character of the title must start with an `Uppercase letter`. + +#### Markdown Example + +``` +# Timer + +The timer module exposes a global API for scheduling functions to be called at some future period of time. +Because the timer functions are globals, there is no need to call require('timers') to use the API. +``` + +## {your_module_name}.{your_module_function_name}([{argument_name}]) +* `{argument_name}` {{Argument_type}} {more information} **Default:** `{defalut_value}` +* Returns: {{return_type}} {more information} + +- Write a description of this function here. +- The first character of Module in the title must start with a `lowercase letter`. +- The other rules are the same as mentioned before. + +**Example** +``` + Write a sample usage for this API if needed. +``` + +#### Markdown Example +``` +### net.connect(port[, host][, connectListener]) +* `port` {number} Port the client should connect to. +* `host` {string} Host the client should connect to. **Default:** `localhost`. +* `connectListener` {Function} Listener for the `'connect'` event. +* Returns {net.Socket}. + +Creates a new `net.Socket` and automatically connects to the supplied `port` and `host`. +If host is omitted, `localhost` will be assumed. +The `connectListener` is automatically registered as a `'connect'` event listener. +``` + +## Class: {Your_class_name} + +- Write a brief description of this class here. +- The first character of the title must start with an `Uppercase letter`. +- While you are writing this description, if you need to write down module / class / function / event name, arguments, or type which you already mentioned, then enclose the keyword in single-quotation. This rule applies to other items as well. + + E.g) The given `callback` is called every `delay` milliseconds. If it's not a function, a `TypeError` will be thrown. + +### new {Your_class_name}([{argument_name}]) +* `{argument_name}` {{Argument_type}} {more information} **Default:** `{defalut_value}` +* Returns: {{return_type}} {more information} + +Notice that every argument name of API and defalut value are in a single-quote. + +**Example** +``` + Write a sample usage for this API if needed. +``` + +#### Markdown Example + +``` +# Class: Buffer + +Buffer class is a global type with various constructors and accessors. +IoT.js provides Buffer to manipulate binary data. Currently buffer has a pure +ES5 compatible implementation, but this might be reworked to use `UInt8Array` in the future. + + +### new Buffer(size) +* `size` {integer} Size of the new buffer. + +Creates a new buffer of `size` bytes and initialize its data to zero. + +``` + + +### {Your_class_name}.{your_static_function_name}([{argument_name}]) +* `{argument_name}` {{Argument_type}} {more information} **Default:** `{defalut_value}` +* Returns: {{return_type}} {more information} + +- Write a description of this static function here. +- The first character of Class in the title must start with an `Uppercase letter`. +- The other rules are the same as mentioned before. + +**Example** +``` + Write a sample usage for this API if needed. +``` + +#### Markdown Example + +``` +### Buffer.byteLength(str, encoding) + +* `str` {string} Source string. +* `encoding` {string} String encoding. +* Returns: {integer} Byte length of source string. + +Returns the byte length of a buffer representing the value +of the string argument encoded with encoding. The effect is +the same as: + +```js +return new Buffer(str, encoding).length; +``` + + +### {your_class_name}.{property_name} +* {{property_type}} + +- Write a description of this property here. +- The first character of the title must start with a `lowercase letter`. + +**Example** +``` + Write a sample usage for this API if needed. +``` +#### Markdown Example +``` +### buf.length +* {integer} + +Returns the capacity of the buffer in bytes. Note: when +the buffer is converted to another type (e.g. `String`) the +length of the converted value might be different from +this value. + +**Example** + +```js +var Buffer = require('buffer'); + +var buffer = new Buffer([0xc8, 0x80]) +console.log(buffer.length); // prints 2 + +var str = buffer.toString(); +console.log(str.length); // prints 1 +``` + + +### {your_class_name}.{your_prototype_function_name}([{argument_name}]) +* `{argument_name}` {{Argument_type}} {more information} **Default:** `{defalut_value}` +* Returns: {{return_type}} {more information} + +- Write a description of this prototype function here. +- The first character of Class in the title must start with a `lowercase letter`. +- The other rules are the same as mentioned before. + +**Example** +``` + Write a sample usage for this API if needed. +``` + +#### Markdown Example + +``` +### emitter.on(event, listener) +* `event` {string} The name of the event. +* `listener` {Function} The callback function. + * `args` {any}. +* Returns `emitter` {events.EventEmitter}. + +Adds the `listener` callback function to the end of the listener's list for the given `event`. No checks are made to see if the `listener` has already been added. +In case of multiple calls the `listener` will be added and called multiple times. + +**Example** + +```js +var EventEmitter = require('events').EventEmitter; +var emitter = new EventEmitter(); + +emitter.on('event', function() { + console.log('emit event'); +}); + +emitter.emit('event'); + +``` + + +### Event: '{your_events_name}' +* `{callback_name}` {{callback_function_argument}} + * `{argument1}` {{argument2_type}} {more information} + +- Write a description of this here. +- In case of Event, the name of Class that this event belongs to, is not prepended in the title. +- The other rules are the same as mentioned before. + +#### Markdown Example + +``` +### Event: 'lookup' +* `callback` {Function} + * `err` {Error} + * `address` {string} + * `family` {string|null} + +Emitted after resolving hostname. +``` + + - Notice that the `err {Error}` above is started with `2 spaces` indentation since it's given to `callback` as parameters, not `lookup` event. diff --git a/docs/devs/Advanced-Development.md b/docs/devs/Advanced-Development.md new file mode 100644 index 0000000000..4e9ff030a1 --- /dev/null +++ b/docs/devs/Advanced-Development.md @@ -0,0 +1,8 @@ + - [Inside IoT.js](Inside-IoT.js.md) + - [Experimental Features](Experimental-Features.md) + - [Logging Execution](Logging-IoT.js-execution.md) + - [Memory saving with libtuv](Memory-savings-with-libtuv.md) + - [Optimization Tips](Optimization-Tips.md) + - [JerryScript Debugger](Use-JerryScript-Debugger.md) + - [Writing New Builtin Module](Writing-New-Builtin-Module.md) + - [Extended API Guidelines](Extended-API-Guidelines.md) diff --git a/docs/help/Coding-Style-Guideline.md b/docs/devs/Coding-Style-Guidelines.md similarity index 89% rename from docs/help/Coding-Style-Guideline.md rename to docs/devs/Coding-Style-Guidelines.md index e9f72561a5..3775ee9ef4 100644 --- a/docs/help/Coding-Style-Guideline.md +++ b/docs/devs/Coding-Style-Guidelines.md @@ -1,8 +1,4 @@ -Coding Style Guideline -====================== - * [Coding Style Guideline for C](#coding-style-guideline-for-c) - * Validated Struct * Header Files * Formatting * Naming @@ -13,21 +9,13 @@ Coding Style Guideline * Naming * Formatting * [Coding Style Guideline for Python](#coding-style-guideline-for-python) - +* [Coding Style Check Tool](#coding-style-check-tool) # Coding Style Guideline for C Our coding style guideline is based on [google c++ coding standard](https://google.github.io/styleguide/cppguide.html), but modified due to some difference between C and C++. -When this guideline is ambiguous, just follow the result of running `./tools/check_tidy.py`. -Here are `./tools/check_tidy.py` options: -``` ---autoedit: Automatically edit the detected clang format errors. No diffs will be displayed. -``` - -## Validated Struct -Use [Validated Struct](../devs/Inside-IoT.js-Validated-Struct.md) whenever possible, for encapsulation and validity check. ## Header Files @@ -133,13 +121,13 @@ Use lower cases and underscore for struct names, and add prefix `iotjs_` and suf ### Function names Use lower cases and underscore for function names. -For constructors, destructor, and methods of validated struct `iotjs_mystruct_t`, use names starting with `iotjs_mystruct_*`. +For constructors and destructor, use names starting with `iotjs_mystruct_*`. Constructor function name should be either `iotjs_mystruct_create` or `iotjs_mystruct_initialize`, depending on whether the constructor returns the instance as return value, or the constructor just initializes the instance passed by parameter. ```c typedef struct { -} IOTJS_VALIDATED_STRUCT(iotjs_mystruct_t); +} iotjs_mystruct_t; iotjs_mystruct_t iotjs_mystruct_create(); // Ok iotjs_mystruct_t* iotjs_mystruct_create(); // Ok @@ -190,7 +178,7 @@ Do not modify prototypes of builtin objects ## Javascript Style Rules ### Naming -Use lowerCamelCase for varible names and function names. +Use lowerCamelCase for variable names and function names. var myFirstVariable; function myFirstFunction { @@ -211,3 +199,21 @@ Follow C/C++ formatting above. # Coding Style Guideline For Python The coding conventions for Python code follows [PEP 8 - Style Guide for Python Code](https://www.python.org/dev/peps/pep-0008/) + + +# Coding Style Check Tool + +When this guideline is ambiguous, just follow the result of running `./tools/check_tidy.py`. +This tool helps you check your code style. You have to install `clang` and `eslint` to use this tool. And [`node.js`](https://nodejs.org/en/download/) should be installed before installing `eslint`. + +```bash +$ sudo apt-get update +$ sudo apt-get install clang-format-3.9 +$ cd iotjs +$ npm install +``` + +Here are `./tools/check_tidy.py` options: +``` +--autoedit: Automatically edit the detected clang format and eslint errors. No diffs will be displayed. +``` diff --git a/docs/help/Developer-Tutorial.md b/docs/devs/Developer-Tutorial.md similarity index 98% rename from docs/help/Developer-Tutorial.md rename to docs/devs/Developer-Tutorial.md index cb7189ff42..b02bf925e7 100644 --- a/docs/help/Developer-Tutorial.md +++ b/docs/devs/Developer-Tutorial.md @@ -158,4 +158,7 @@ Hello, IoT.js! 3 undefined ``` -Note that `console.log(local)` prints `undefined`. It cannot be referred because it is not added in `exports`. \ No newline at end of file +Note that `console.log(local)` prints `undefined`. It cannot be referred because it is not added in `exports`. + +See also: +* [How to write a new module](Writing-New-Module.md) diff --git a/docs/help/Development-Process.md b/docs/devs/Development-Process.md similarity index 89% rename from docs/help/Development-Process.md rename to docs/devs/Development-Process.md index 707b2d7628..f1f7ffcd70 100644 --- a/docs/help/Development-Process.md +++ b/docs/devs/Development-Process.md @@ -11,7 +11,7 @@ Individual developers maintain a local copy of the IoT.js codebase using the git ### Proposals, Get Answers and Report a Bug via Github Issues -If you have a question about IoT.js code, have trouble any documentation, would like to suggest new feature, or find a bug, [review the current IoT.js issues](https://github.com/Samsung/iotjs/issues) in GitHub, and if necessary, [create a new issue](https://github.com/Samsung/iotjs/issues/new). +If you have a question about IoT.js code, have trouble any documentation, would like to suggest new feature, or find a bug, [review the current IoT.js issues](https://github.com/jerryscript-project/iotjs/issues) in GitHub, and if necessary, [create a new issue](https://github.com/jerryscript-project/iotjs/issues/new). **There are several labels on the Issue. Please choose proper labels on the purpose.** * **bug** @@ -56,14 +56,14 @@ The IoT.js Project development process is marked by the following highlights: ### Tips on GitHub Issues -* Check existing [IoT.js issues](https://github.com/Samsung/iotjs/issues) for the answer to your issue. +* Check existing [IoT.js issues](https://github.com/jerryscript-project/iotjs/issues) for the answer to your issue. Duplicating an issue slows you and others. Search through open and closed issues to see if the problem you are running into has already been addressed. -* If necessary, [open a new issue](https://github.com/Samsung/iotjs/issues/new). - - Clearly describe the issue. +* If necessary, [open a new issue](https://github.com/jerryscript-project/iotjs/issues/new). + - Clearly describe the issue. + What did you expect to happen? + What actually happened instead? + How can someone else recreate the problem? - Include system details(such as the hardware, library, and operating system you are using and their versions). - - Paste error output and logs in the issue or in a Gist(https://gist.github.com/). + - Paste error output and logs in the issue or in a Gist(https://gist.github.com/). -For more information about GitHub issues, refer to the [GitHub issues guidelines](https://guides.github.com/features/issues/). \ No newline at end of file +For more information about GitHub issues, refer to the [GitHub issues guidelines](https://guides.github.com/features/issues/). diff --git a/docs/devs/Enabling-Experimental-Feature.md b/docs/devs/Experimental-Features.md similarity index 88% rename from docs/devs/Enabling-Experimental-Feature.md rename to docs/devs/Experimental-Features.md index b905bdefa7..87bf0b60b5 100644 --- a/docs/devs/Enabling-Experimental-Feature.md +++ b/docs/devs/Experimental-Features.md @@ -8,17 +8,17 @@ Experimental build is an executable IoT.js including features that are not yet r ## How to make IoT.js experimental build -You need to make IoT.js using our build script, ["build.py"](https://github.com/Samsung/iotjs/blob/master/tools/build.py), with `--experimental` or `-e` option. +You need to make IoT.js using our build script, ["build.py"](https://github.com/jerryscript-project/iotjs/blob/master/tools/build.py), with `--experimental` or `-e` option. ```bash tools/build.py --experimental - tools/build.py -e --iotjs-include-module experimental-module + tools/build.py -e --cmake-param=-DENABLE_MODULE_EXPERIMENTAL-MODULE=ON tools/build.py -e --config=build.experimental.config ``` - For selecting modules to be included, you need to notify the script where your modules exist. You can use `--iotjs-include-module` or `--config` option for that. For further information, please refer to [Writing Builtin JavaScript Module](https://github.com/Samsung/iotjs/blob/master/docs/devs/Writing-New-Builtin-Module.md#writing-builtin-javascript-module). + For selecting modules to be included, you need to notify the script where your modules exist. You can use `--iotjs-include-module` or `--config` option for that. For further information, please refer to [Writing Builtin JavaScript Module](https://github.com/jerryscript-project/iotjs/blob/master/docs/devs/Writing-New-Builtin-Module.md#writing-builtin-javascript-module). ## Writing Code diff --git a/docs/help/Extended-API-Guideline.md b/docs/devs/Extended-API-Guidelines.md similarity index 65% rename from docs/help/Extended-API-Guideline.md rename to docs/devs/Extended-API-Guidelines.md index 3400cbb751..b84a8605dc 100644 --- a/docs/help/Extended-API-Guideline.md +++ b/docs/devs/Extended-API-Guidelines.md @@ -1,6 +1,3 @@ -Extended API Guideline -====================== - Basically, our basic APIs are based on node.js. They will follow same form with node.js because of compatibility.
However, extended APIs need a guideline because they are implemented by many contributor. (for consistent usability) @@ -8,29 +5,31 @@ However, extended APIs need a guideline because they are implemented by many con # Ground Rules ## API naming rules -1. The APIs which have similar role should have same API name. +1. The APIs which have similar role should have same API name. 2. Basically, all APIs are async API. If you want to make sync API, you need to add `Sync` as a suffix.
For example, `readSync()`, `writeSync()`, and so on. -## Generating an object -1. The module object should be generated using `open()` API for consistent usability. (Do not use `New` constructor) -2. `open()` API should have configuable as first argument and callback function as second argument.
callback function is always optional. +## Creating a module object +1. The module object should be generated using `open()` API for consistent usability. +2. `open()` API should have configurable as first argument and callback function as second argument.
callback function is always optional. For example, GPIO module generate an object like below: ```javascript var gpio = require('gpio'); - -var gpio10 = gpio.open({pin: 10, direction: gpio.DIRECTION.OUT}, +var gpio10 = gpio.open({pin: 10, direction: gpio.DIRECTION.OUT}, function(err){console.log(err);}); +gpio10.writeSync(1); ``` ## Minimize event generation 1. The response of the API call uses callback function. 2. Only generate event when user need to know something without any API call. -3. The event which have similar role should have same event name. +3. The event which has similar role should have same event name. ## Error generation 1. `error` can be generated in both JS/native side. -2. The `error` shoud be created in the place where it occurs. +2. The `error` should be created in the place where it occurs. +3. In the asynchronous function, the first parameter of callback indicates an error. +If it is null, the function works without error. For example, error can be generated like below: @@ -38,9 +37,8 @@ In native side, ```c iotjs_jargs_t jargs = iotjs_jargs_create(2); -// kGpioErrRead: int -if (result == kGpioErrRead) { - iotjs_jargs_append_error_with_code(&jargs, "GPIO Error", kGpioErrRead); +if (!result) { + iotjs_jargs_append_error(&jargs, "GPIO Error"); } ``` @@ -58,6 +56,5 @@ if (!util.isNumber(value)) { # Recommended Rules -1. Call `close()` api when process module occur `exit` event. -2. If it is possible, use the functions provided by `libtuv` (File open, read, write, etc.) -3. Callback function in API argument should be always optional. +1. If it is possible, use the functions provided by `libtuv` (File open, read, write, etc.) +2. Callback function in API argument should be always optional. diff --git a/docs/devs/Inside-IoT.js-Validated-Struct.md b/docs/devs/Inside-IoT.js-Validated-Struct.md deleted file mode 100644 index 97341be843..0000000000 --- a/docs/devs/Inside-IoT.js-Validated-Struct.md +++ /dev/null @@ -1,195 +0,0 @@ -Validated Struct -================ - -Validated struct is C struct wrapper for encapsulation and validity check. - -* Validated Struct Declaration -* Constructors, Destructor, Methods -* Ownership of validated struct instance - * Case 1: Validated struct instance as local variable - * Case 2: Validated struct instance as parameter & return - * Case 3: Validated struct instance as member variable of other struct - * Case 4: Validated struct instance as data of asynchronous execution - -# Validated Struct Declaration - -```c -typedef struct { - int a; - void* b; -} IOTJS_VALIDATED_STRUCT(iotjs_myclass_t); -``` - -Above struct will make the member variable encapsulated by wrapping real members with wrapper like below. - -```c -typedef struct { - int a; - void* b; -} iotjs_myclass_t_impl_t; - -typedef struct { - iotjs_myclass_impl_t unsafe; - /* More members for struct validity check exist in debug mode */ -} iotjs_myclass_t; - -int main() { - iotjs_myclass_t x; -} -``` - -Only wizards will access the members directly by using `x.unsafe.a`, `x.unafe.b`, ... . Otherwize the members are only accessible with its accessor function. - -See `src/iotjs_def.h` for more details on real implementation. - -# Constructors, Destructor, Methods - -You should create C++-like constructors, destructor and methods with provided accessor. Then you can access the encapsulated member variables using `_this` variable, which has almost same role with C++ `this` keyword. -You must call `destroy` for every validated structs you've created. - -```c -/* Constructor */ -iotjs_myclass_t iotjs_myclass_create(int a) { - iotjs_myclass_t instance; - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_myclass_t, &instance); - - _this->a = a; - _this->b = malloc(a); - - return instance; -} - -/* Destructor */ -void iotjs_myclass_destroy(iotjs_myclass_t* instance) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_myclass_t, instance); - free(_this->b); -} - -/* Method */ -int iotjs_myclass_get_a(iotjs_myclass_t* instance) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_myclass_t, instance); - return _this->a; -} - -int main() { - /* Validated struct as local variable */ - iotjs_myclass_t local_instance = iotjs_myclass_create(3); - printf("%d\n", iotjs_myclass_get_a(&local_instance)); - iotjs_myclass_destroy(&local_instance); - return 0; -} -``` - -# Ownership of validated struct instance - -The ground rule is: - -* Use `iotjs_classname_t` typed variable if the variable *is* responsible for destruction of instance. -* Use `iotjs_classname_t*` typed variable if the variable *is not* responsible for destruction of instance. - -Below Case 1 ~ Case 4 shows the case-by-case example of the ownership rule. - -## Case 1: Validated struct instance as local variable -The `local_instance` variable in previous example was the local instance of validated struct. -Since `local_instance` should be destructed inside the function scope, `iotjs_myclass_t` type was used. - -## Case 2: Validated struct instance as parameter & return -Previous example also included the example of validated struct instance as parameter and return. -When accessing member variable `a` by calling `iotjs_myclass_get_a()`, -`iotjs_myclass_t*` type was used as the parameter type, since it *does not* move the responsibility to destruct the instance. - -And when returning the newly created instance by calling `iotjs_myclass_create()`, -`iotjs_myclass_t` type was used as return type, since it *does* move the responsibility to destruct the instance. - -## Case 3: Validated struct instance as member variable of other struct - -```c -/* Validated struct as member variable of other struct */ - -typedef struct { - iotjs_myclass_t member_instance; -} IOTJS_VALIDATED_STRUCT(iotjs_otherclass_t) - -iotjs_otherclass_t iotjs_otherclass_create() { - /* Initialization steps for iotjs_otherclass_t */ - _this->member_instance = iotjs_myclass_create(3); -} - -void iotjs_otherclass_destroy() { - /* Finalization steps for iotjs_otherclass_t */ - iotjs_myclass_destroy(&_this->member_instance); -} -``` - -In the case above, `iotjs_myclass_t` instance is used as member variable of other class. -Since `iotjs_otherclass_t` is responsible for finalizing the `member_instance`, -it owns the variable as `iotjs_myclass_t` type, not pointer type. - -## Case 4: Validated struct instance as data of asynchronous execution -Another usecase would be using validated struct as callback data. -Currently, our all asynchronous datas are wrapped with `iotjs_*wrap_t` type, -and they are destructed automatically. - -```c -/* - * Public APIs in iotjs_module_fs.h - */ - -typedef struct { - iotjs_reqwrap_t reqwrap; - uv_fs_t req; -} IOTJS_VALIDATED_STRUCT(iotjs_fsreqwrap_t); - -iotjs_fsreqwrap_t* iotjs_fsreqwrap_create(const iotjs_jval_t* jcallback); -void iotjs_fsreqwrap_dispatched(iotjs_fsreqwrap_t* fsreqwrap); -``` - -As you can see, constructor returns the `iotjs_fsreqwrap_t*` type, -because it does not pass the responsibility to destruct the return value. -It is destructed when request is dispatched, which can be informed by calling `iotjs_fsreqwrap_dispatched()`. -The destructor `iotjs_fsreqwrap_destroy()` is hidden in c file. - -```c -/* - * Implementation in iotjs_module_fs.c - */ - -iotjs_fsreqwrap_t* iotjs_fsreqwrap_create(const iotjs_jval_t* jcallback) { - iotjs_fsreqwrap_t* fsreqwrap = IOTJS_ALLOC(iotjs_fsreqwrap_t); - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_fsreqwrap_t, fsreqwrap); - iotjs_reqwrap_initialize(&_this->reqwrap, jcallback, (uv_req_t*)&_this->req); - return fsreqwrap; -} - -static void iotjs_fsreqwrap_destroy(iotjs_fsreqwrap_t* fsreqwrap) { // private function - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_fsreqwrap_t, fsreqwrap); - uv_fs_req_cleanup(&_this->req); - iotjs_reqwrap_destroy(&_this->reqwrap); - IOTJS_RELEASE(fsreqwrap); -} - -void iotjs_fsreqwrap_dispatched(iotjs_fsreqwrap_t* fsreqwrap) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_fsreqwrap_t, fsreqwrap); - iotjs_fsreqwrap_destroy(fsreqwrap); -} - -/* - * Use of iotjs_fsreqwrap_t - */ - -void callback(uv_fs_t* req) { - do_something(req); - iotjs_fsreqwrap_dispatched(req); /* Call iotjs_*reqwrap_dispatched() when callback called */ -} - -void request(iotjs_jval_t* jcallback) { - iotjs_fsreqwrap_t* wrap = iotjs_fsreqwrap_create(jcallback); - uv_fs_request(loop, wrap->req, callback); -} -``` - -In the case of tuv request wrapper, `iotjs_*reqwrap_dispatched()` should be called when the request has been dispatched. -In the case of tuv handle wrapper, `iotjs_handlewrap_close()` should be called when the handle has been closed. -in the case of JavaScript object wrapper, you don't have to do anything because JavaScript engine will call the destructor when the object becomes inaccessible. - - diff --git a/docs/devs/Inside-IoT.js.md b/docs/devs/Inside-IoT.js.md index e904713592..f032944339 100644 --- a/docs/devs/Inside-IoT.js.md +++ b/docs/devs/Inside-IoT.js.md @@ -3,18 +3,16 @@ Inside IoT.js * [Design](#design) * [Javascript Binding](#javascript-binding) - * iotjs_jval_t - * iotjs_jobjectwrap_t - * Native handler - * Embedding API + * [jerry_value_t](#jerry_value_t) + * [Native handler](#native-handler) + * [Embedding API](#embedding-api) * [libuv Binding](#libuv-binding) - * iotjs_handlewrap_t - * iotjs_reqwrap_t + * [iotjs_handlewrap_t](#iotjs_handlewrap_t) + * [iotjs_reqwrap_t](#iotjs_reqwrap_t) * [IoT.js Core](#iotjscoe) - * Life cycle of IoT.js - * Builtin - * Native module - * Event loop + * [Life cycle of IoT.js](#life-cycle-of-iot.js) + * [Builtin modules](#builtin-modules) + * [Event loop](#event-loop) # Design @@ -37,9 +35,9 @@ Although IoT.js only supports JerryScript for now, there will be a chance that w For this reason, we want to keep the layer independent from a specific Javascript engine. You can see interface of the layer in [iotjs_binding.h](../../src/iotjs_binding.h). -## iotjs_jval_t +## jerry_value_t -`iotjs_jval_t` struct stands for a real Javascript object. Upper layers will access Javascript object via this struct. +`jerry_value_t` struct stands for a real Javascript object. Upper layers will access Javascript object via this struct. This struct provides following functionalities: * Creating a Javascript object using `iotjs_jval_create_*()` constructor. @@ -55,45 +53,6 @@ This struct provides following functionalities: * Evaluating a Javascript script. * Set and Get corresponding native data to the Javascript object. -## iotjs_jobjectwrap_t - -You can refer Javascript object from C code side using `iotjs_jval_t` as saw above. -When a reference for a Javascript object was made using `iotjs_jval_t`, it will increase the reference count and will decrease the count when it goes out of scope. - -```c -{ - // Create JavaScript object - // It increases reference count in JerryScript side. - iotjs_jval_t jobject = iotjs_jval_create(); - - // Use `jobject` - ... - - // Before jobject goes out of scope, destroy it. - // It decreases reference count in JerryScript side so that it can be GC-ed. - iotjs_jval_destroy(&jobject) -} -``` - -But the situation is different if you want to refer a Javascript object through out program execution until the object is live. -You may write code like this: - -```c - iotjs_jval_t* jobject = (iotjs_jval_t*)malloc(sizeof(iotjs_jval_t)); // Not allowed -``` - -Unfortunately, we strongly do not recommend that kind of pattern. We treat pointer-types variables in special way. (See [Validated Struct](Inside-IoT.js-Validated-Struct.md) for more details.) - -To achieve your wish, we recommend using `iotjs_jobjectwrap_t` for that purpose. -`iotjs_jobjectwrap_t` is kind of weak pointer to a Javascript Object. -It refers a Javascript object but never increase reference count so that Javascript engine can collect the object when it turns into garbage. -The `iotjs_jobjectwrap_t` instance will be released at the time the corresponding Javascript object is being reclaimed. - -Do not hold pointer to the wrapper in native code side globally because even if you are holding a wrapper by pointer, Javascript engine probably releases the corresponding Javascript object resulting deallocation of wrapper. Consequentially your pointer will turned into dangling. - -The only safe way to get wrapper is to get it from Javascript object. When a wrapper is being created, it links itself with corresponding Javascript object with `iotjs_jval_set_object_native_handle()` method of `iotjs_jval_t`. And you can get the wrapper from the object with `iotjs_jval_get_object_native_handle()` method of `iotjs_jval_t` later when you need it. - - ## Native handler Some operations - such as file I/O, networking, device control, multitasking, and etc - can not be performed by pure Javascript. @@ -110,7 +69,7 @@ Whereas native handler does know that it is being called from Javascript (actual ## Embedding API -Many Javascript engines these days provide embedding API. IoT.js uses the API to create [builtin module](#builtin) and [native handler](#native-handler). See following link if you want further information about the API: +Many Javascript engines these days provide embedding API. IoT.js uses the API to create [builtin module](#builtin-modules) and [native handler](#native-handler). See following link if you want further information about the API: * [JerryScript API](http://jerryscript.net/api-reference) * [Duktape API](http://duktape.org/api.html) * [V8 embedder's guide](https://developers.google.com/v8/embed) @@ -128,7 +87,7 @@ You can read [libuv design document](http://docs.libuv.org/en/v1.x/design.html) `iotjs_handlewrap_t` is to bind a Javascript object and a libuv handle (e.g. file descriptor) together. `iotjs_handlewrap_t` inherits `iotjs_jobjectwrap_t` since it is linked with a Javascript object. -Unlike `iotjs_jobjectwrap_t`, `iotjs_jobjectwrap_t` increases RC for the Javascript object when an instance of it is created to prevent GC while the handle is alive. The reference counter will be decreased after the handle is closed, allowing GC. +Unlike `iotjs_jobjectwrap_t`, `iotjs_handlewrap_t` increases RC for the Javascript object when an instance of it is created to prevent GC while the handle is alive. The reference counter will be decreased after the handle is closed, allowing GC. ## iotjs_reqwrap_t @@ -176,23 +135,18 @@ The process of IoT.js can be summarized as follow: 6. Run [event loop](#event-loop) until there are no more events to be handled. 7. Clean up. -## Builtin +## Builtin modules -"Builtin" is Javascript objects fully implemented in C using [embedding API](#embedding-api). -The list of builtin objects can be found at `MAP_MODULE_LIST` macro in ['iotjs_module.h'](../../src/iotjs_module.h). +"Builtin" is Javascript objects implemented in C using [embedding API](#embedding-api), in Javascript or both. +The list of builtin objects can be found in ['modules.json'](../../src/modules.json). -Because methods of builtin modules are implemented as [native handler](#native-handler), +Native parts of builtin modules are implemented as [native handler](#native-handler), so they are able to access underlying system using libuv, C library, and system call. -Also, builtin modules could be used for optimizing performance of CPU bound routine or reduce binary size. - -Builtin modules are initialized during [intializing step of IoT.js](#life-cycle-of-iotjs) and released just before program terminates. - -## Native module -The [basic modules and extended modules](../api/IoT.js-API-reference.md) provided by IoT.js are called 'native module' because it will be included IoT.js as binary format.(not as script). -There is a [tool](../../tools/js2c.py) that transfer Javascript script source file into C file. -Usually a native module needs help from couple of [builtin](#builtin) modules which are implemented in C thus able to access underlying system. +The [basic modules and extended modules](../api/IoT.js-API-reference.md) provided by IoT.js are called 'Builtin module' because it will be included in the IoT.js binary. +There is a [tool](../../tools/js2c.py) that transfer Javascript script source file into C file +and this C file will be compiled into the IoT.js binary. Some native modules are bound to global object while others are on demand. On demand modules will be created at the moment when it is first required and will not released until the program terminates. @@ -257,7 +211,7 @@ And calling the javascript callback function with the result. ```c iotjs_fsreqwrap_t* req_wrap = (iotjs_fsreqwrap_t*)(req->data); // get request wrapper - const iotjs_jval_t* cb = iotjs_fsreqwrap_jcallback(req_wrap); // javascript callback function + const jerry_value_t* cb = iotjs_fsreqwrap_jcallback(req_wrap); // javascript callback function iotjs_jargs_t jarg = iotjs_jargs_create(2); iotjs_jargs_append_null(&jarg); // in case of success. diff --git a/docs/help/IoT.js-Developer's-Certificate-of-Origin-1.0.md b/docs/devs/IoT.js-Developer's-Certificate-of-Origin-1.0.md similarity index 100% rename from docs/help/IoT.js-Developer's-Certificate-of-Origin-1.0.md rename to docs/devs/IoT.js-Developer's-Certificate-of-Origin-1.0.md diff --git a/docs/devs/IoT.js-Module-Generator.md b/docs/devs/IoT.js-Module-Generator.md new file mode 100644 index 0000000000..075ecdcfb0 --- /dev/null +++ b/docs/devs/IoT.js-Module-Generator.md @@ -0,0 +1,732 @@ +# C/C++ API to IoT.js module generator + +The module generator is an automatic code generating tool, which gives help for developers to avoid writing lots of code. It generates a binding layer between a C/C++ API and the IoT.js framework and creates a native module which can be easily imported and used in JavaScript. + +**NOTE:** The tool can't handle perfect when there are complex user-defined types, pointers to structures, multiple indirections etc. in the native library. + +The input of the generator is a directory, which contains the C/C++ header files and the static library of the API. + +1. [Dependencies](#dependencies) +2. [Features](#features) + - [Classes](#classes) + - [Functions](#functions) + - [Variables](#variables) + - [Enums](#enums) + - [Macros](#macros) + - [Namespaces](#namespaces) +3. [Supported types](#supported-types) + - [Examples](#examples) +4. [Usage](#usage) + - [Optional arguments](#optional-arguments) +5. [Quick example](#quick-example) + +## Dependencies: + +The tool uses libclang to analyze the given library and get the necessary informations. + +### Clang library: + +#### Linux: + +```bash +apt install libclang1-6.0 +``` +**NOTE:** The python binding searches for `libclang.so` as deafult. After installing `libclang1-6.0` you should add a symlink to `path/to/libclang-6.0.so` like below: + +```bash +cd /usr/lib/x86_64-linux-gnu/ +sudo ln -s libclang-6.0.so libclang.so +``` + +#### Windows: + +[Download link](http://releases.llvm.org/6.0.0/LLVM-6.0.0-win32.exe) + +**NOTE:** The tool has been tested with 32 bit binary. You should add LLVM to the system PATH, so python binding can find it. + +### Python binding for Clang: + +```bash +pip install clang +``` + +or optionally for Linux: +```bash +apt install python-clang-6.0 +``` + +## Features: + +The C/C++ library is represented as an object in the JavaScript environment. This object is the result of the `require` function call with the right module name parameter. The generated module name is the name of the input folder with `'_module'` suffix. If the input folder is `my_api` then you can load the module with the code below: + +```javascript +var lib = require('my_api_module'); +``` + +#### Classes: + +If there is a class in the C++ library, the module object has a property with the name of the class, which is a constructor. You can create an object in JavaScript, if you call the constructor with the right parameters. The returned JavaScript variable has some properties, which are represent the members and methods of the class. + +C++ header: +```cpp +class MyClass { + int x; +public: + MyClass(): x(0) {} + MyClass(int x): x(x) {} + + void foo(void); // print x +}; +``` +JS file: +```javascript +var cpp_lib = require('module_name'); + +var obj1 = new cpp_lib.MyClass(); +var obj2 = new cpp_lib.MyClass(42); + +obj1.foo(); // print 0 +obj2.foo(); // print 42 +``` + +#### Functions: + +Every function from the C/C++ library are represented as properties of the library object. + +**C :** + +If there is a declaration, like `void foo(int);` in the C library, then the object has a property with the name `foo`. + +```javascript +var c_lib = require('module_name'); +c_lib.foo(42); // call the C function +``` + +**C++ :** + +The different between C and C++ functions, that you can call C++ functions with the same name, but with different parameter lists. If there is a declaration, like `void foo(int = 0);` in the C++ library, you can use it as below. It works in the case of constructors and methods too. + +```javascript +var cpp_lib = require('module_name'); +cpp_lib.foo(); // call the C++ function with the default parameter +cpp_lib.foo(42); +``` + +**NOTE**: There are cases when you can't decide on the API side what is the real type of a JavaScript value. For example there are two overloads of a C++ function: + +`void f(int);` + +`void f(double);` + +In the binding layer you can check that the parameter is a number or not, but you don't know it is an integer or a floating point number, so it isn't clear which overload you should call. The generator's solution for the problem is using suffixes. If you generate the binding layer for the example code above you will get a message like that: +``` +WARN: The following overload of f has been renamed to f_$0 : +void f ( int ) +WARN: The following overload of f has been renamed to f_$1 : +void f ( double ) +``` +The rigth usage of the **f** function in that case is the following: +```javascript +var cpp_lib = require('module_name'); +cpp_lib.f_$0(1); // Use f_$0 with integer parameter +cpp_lib.f_$1(1.5); // Use f_$1 with floating point parameter +``` + + +#### Variables: + +The global variables of the C/C++ library are also represented as properties. If there is a declaration, like `int a;` in the C library, then the object has a property with the name `a`, and you can get and set its value, but if there is a definition, like `const int b = 42;` you can only read the value from the property and you can not modify it. + +C/C++ header: +```c +int i; +``` + +JS file: +```javascript +var lib = require('module_name'); +lib.i = 1; // set the value of 'i' +console.log(lib.i); // print 1 +``` + +#### Enums: + +Enums work like constants above. You can read the value of the enumerator from a property, but you can not modify it. + +C/C++ header: +```c +enum abc {A, B, C}; +``` + +JS file: +```javascript +var lib = require('module_name'); +console.log(lib.A); // print 0 +console.log(lib.B); // print 1 +console.log(lib.C); // print 2 +``` + +#### Macros: + +Macros also work like constants. You can read the value of the macro from a property, but you can not modify it. There are three supported macro types. +* If the macro defines a character literal, like `#define C 'c'`. +* If the macro defines a string literal, like `#define STR "str"`. +* If the macro defines a numeric literal, or contains some kind of operation, but the result is a number, like `#defines ZERO 0` or `#define TWO 1 + 1`. It also works, if the macro contains other macro identifiers. + +C/C++ header: +```c +#define ONE 1 +#define TWO 2 +#define THREE ONE + TWO +``` + +JS file: +```javascript +var lib = require('module_name'); +console.log(lib.ONE); // print 1 +console.log(lib.TWO); // print 2 +console.log(lib.THREE); // print 3 +``` + +#### Namespaces: + +In JavaScript a namespace represented as an object, which is set to another object as property. Concretely to the object, which represent the scope where the namespace is. + +C++ header: +```c +namespace my_ns { + void foo(void); + + namespace nested { + void foo(void); + } +} +``` + +JS file: +```javascript +var cpp_lib = require('module_name'); + +cpp_lib.my_ns.foo(); // my_ns::foo + +with (lib.my_ns.nested) { + foo(); // my_ns::nested::foo +} +``` + +**NOTE**: If there is a `using` command for a namespace in the native header, you also have to call functions etc. through the namespace object. You can use `with` in JavaScript to reduce the code. + +## Supported types: + +The table below shows which JavaScript type represent the particular C/C++ type. + +### Fundamental types: + +| C/C++ type | JS type | +| - | - | +| void | undefined | +| char | one length String | +| integers (short/int/long etc.) | Number | +| enum | Number | +| float / double | Number | +| _Bool / bool | Boolean | + +### Record types: + +If you would like to create a record type variable you have to call a constructor through the library object. + +| C/C++ type | JS type | +| - | - | +| struct / union / class | Object | + +### Pointer types: + +If there is a char* or a pointer to a number (short/int/float etc.) in a native function's parameter list and you call this function from JavaScript with a String or TypedArray the binding layer alloc memory for the native pointers. If after the native call the pointers won't be used you should modify the source code of the binding layer and free them. + +| C/C++ type | JS type | +| - | - | +| char* | String / Null | +| signed char* | Int8Array | +| unsigned char* | Uint8Array | +| short* | Int16Array | +| unsigned short* | Uint16Array | +| int* / long* / long long* | Int32Array | +| unsigned int* / unsigned long* / unsigned long long* | Uint32Array | +| float* | Float32Array | +| double* / long double* | Float64Array | +| function pointer (only as function parameter) | Function / Null | +| record pointer (only as function parameter) | Object / Null | + +**NOTE**: Other types are not supported, which means that you need to implement how you would like to use these parts of the C/C++ API. + +#### Examples: + +##### `void` +```c +void f(void); +``` +```javascript +var a = lib.f(); // 'a' == undefined +``` + +##### `char` +```c +char c; +char f(char); +``` +```javascript +lib.c = 'c'; +var a = lib.f('b'); +``` + +##### `integers` +```c +int i; +int f(int); +``` +```javascript +lib.i = 42; +var a = lib.f(5); +``` + +##### `enum` +```c +typedef enum {A, B, C} my_enum; +my_enum e; +my_enum f(my_enum); +``` +```javascript +lib.e = lib.B; +var a = lib.f(lib.A); +``` + +##### `float/double` +```c +float f; +double d; +float f(float); +double g(double); +``` +```javascript +lib.f = 1.5; +lib.d = 2.5; +var f = lib.f(1.5); +var d = lib.g(lib.d); +``` + +##### `bool` +```c +_Bool b; +_Bool f(_Bool); +``` +```javascript +lib.b = true; +var a = lib.f(false); +``` + +##### `char*/char[]` + +If there is global pointer to a char, its value can be `null` or a `String`. + +```c +char * c_ptr; +char c_arr[6]; +char* f(char*); +char* g(char[5]); +``` +```javascript +lib.c_ptr = 'some string'; +// lib.c_arr = 'maximum string length is 5'; NOT WORK +lib.c_arr = 'works'; +var f = lib.f('other string'); // returned value can be null or String +var g = lib.g('1234'); +``` + +##### `int*/int[]` + +If there is global pointer to a number, its value can be `null` or a `TypedArray`. If there is an array of numbers, it will be a `TypedArray` in the JS environment, and you can set the values by indexing. + +```c +int * i_ptr; +int i_arr[5]; +int* f(int*); +int* g(int[5]); +``` +```javascript +var typed_array = new Int32Array(new ArrayBuffer(8), 0, 2); +typed_array[0] = 10; +typed_array[1] = 20; +lib.i_ptr = typed_array; +lib.i_ptr = null; +// lib.i_arr = typed_array; NOT WORK +lib.i_arr[0] = 1; +lib.i_arr[1] = 2; +lib.i_arr[2] = 3; +var f = lib.f(null); // returned value can be null or TypedArray +var g = lib.g(typed_array); +``` + +##### `function` + +Function pointers supported as parameters. There can be cases when it does not work correctly, if the function will be called asynchronous. + +```c +typedef int (callback)(void); + +int f(callback c) { + return c(); +} +``` +```javascript +var a = lib.f(function () { + return 42; +}); +``` + +Let's see a dummy example, when function pointers work incorrectly. + +```c +typedef void (cb)(void); + +cb cb_arr[2]; + +void foo(cb c) { + static int i = 0; + cb_arr[i++] = c; +} + +void bar(void) { + cb_arr[0](); +} +``` +```javascript +lib.foo(function() { + console.log('first callback'); +}); + +lib.foo(function() { + console.log('second callback'); +}); + +// the second foo call overwrite the first callback function +// it will print 'second callback', which is not the expected +lib.bar(); +``` + +##### `struct / union / class` + +```cpp +typedef struct { + int i; + char c; +} S; + +typedef union { + int i; + char c; +} U; + +class C { + int i = 42; +public: + int get_i() {return i;} +}; + +S s; +U u; +C c; +S f(S); +U g(U); +C h(C); +void ptr(S*); +``` +```javascript +var s = new lib.S(); +var u = new lib.U(); +var c = new lib.C(); + +s.i = 42; +s.c = 's'; +lib.s = s; +lib.s.i = 0; + +// var o = { +// i: 42, +// c: 'o' +// } +// +// lib.f(o); NOT WORK 'o' is not a valid S type object +var other_s = lib.f(s); +var other_u = lib.g(u); +var other_c = lib.h(c); +lib.ptr(s); + +console.log(lib.c.get_i()); +``` + +## Usage: + +You can generate a module using the following command: + +```bash +# assuming you are in iotjs folder +$ tools/iotjs-generate-module.py [OPTIONS] +``` + +The `` should contain the header files and the static library of the C/C++ API. `` is the language of the API, which can be `c` or `c++`. These are required arguments for the script. The script generates the source files to the `iotjs/tools/module_generator/output/_module/` folder. The module name will be `_module`. If you would like to modify how the module should work, you have to make some changes in the generated `.c` or `.cpp` file. + +#### Optional arguments: + +The script has some optional arguments, which are the following: + +##### `--out-dir` + +The output folder of the generated module. Default is `tools/module_generator/output` + +```bash +$ tools/iotjs-generate-module.py --out-dir +``` + +##### `--off` +* `functions` | `variables` | `enums` | `macros` + +Turn off the processing of the given part of the API, which means that the script will not generate any code for this part, so you can not use this in the JS environment. + +```bash +$ tools/iotjs-generate-module.py --off=enums --off=macros +``` + +##### `--define` + +Define a macro for the clang preprocessor. + +```bash +$ tools/iotjs-generate-module.py --define FOO --define BAR=42 +``` + +##### `--defines` + +A file, which contains macro definitions for the clang preprocessor. + +`macro_defines.txt`: +```txt +FOO +BAR=42 +``` + +```bash +$ tools/iotjs-generate-module.py --defines macro_defines.txt +``` + +##### `--include` + +Add include path to search for other files. + +```bash +$ tools/iotjs-generate-module.py --include path/to/the/include/folder/ +``` + +##### `--includes` + +A file, which contains include paths. + +`includes.txt`: +```txt +path/to/include/folder +other/path/to/other/folder +``` + +```bash +$ tools/iotjs-generate-module.py --includes includes.txt +``` + +## Quick example: + +#### Directory structure: + +* iotjs/ +* my_api/ + * foo/ + * foo.h + * bar.h + * libexample.a + +#### Header files: + +foo.h: +```c +#define N 10 +int foo(int x); //return x+x +``` + +bar.h: +```c +typedef enum {A, B, C} flags; +void bar(); // print "Hello!" +``` + +#### Build: +```bash +# assuming you are in iotjs folder +$ tools/iotjs-generate-module.py ../my_api/ c +tools/build.py --external-module=tools/module_generator/output/my_api_module --cmake-param=-DENABLE_MODULE_MY_API_MODULE=ON +``` + +#### Usage: +api.js: +```javascript +// the name of the module is same as the directory name with '_module' suffix +var c_lib = require('my_api_module'); +var x = c_lib.foo(2); +console.log(x); // print 4 +c_lib.bar(); // print 'Hello!' +console.log(c_lib.N); // print 10 +console.log(c_lib.B); // print 1 +``` + +#### Generated binding layer: +my_api_js_binding.c: +```c +#include +#include +#include "jerryscript.h" +#include "my_api_js_binding.h" + + +// external function for API functions or for getters / setters +jerry_value_t bar_handler (const jerry_value_t function_obj, + const jerry_value_t this_val, + const jerry_value_t args_p[], + const jerry_length_t args_cnt) +{ + + // check the count of the external function's arguments + if (args_cnt != 0) + { + char const *msg = "Wrong argument count for bar(), expected 0."; + return jerry_create_error (JERRY_ERROR_TYPE, (const jerry_char_t*)msg); + } + + // native function call + bar (); + + + jerry_value_t ret_val = jerry_create_undefined (); + + return ret_val; +} + + +// external function for API functions or for getters / setters +jerry_value_t foo_handler (const jerry_value_t function_obj, + const jerry_value_t this_val, + const jerry_value_t args_p[], + const jerry_length_t args_cnt) +{ + + // check the count of the external function's arguments + if (args_cnt != 1) + { + char const *msg = "Wrong argument count for foo(), expected 1."; + return jerry_create_error (JERRY_ERROR_TYPE, (const jerry_char_t*)msg); + } + + + // check the type of a jerry_value_t variable + if (!jerry_value_is_number (args_p[0])) + { + char const *msg = "Wrong argument type for foo(), expected number."; + return jerry_create_error (JERRY_ERROR_TYPE, (const jerry_char_t*)msg); + } + + // create an integer / floating point number from a jerry_value_t + int arg_0 = (int)jerry_get_number_value (args_p[0]); + + // native function call + int result = foo (arg_0); + + + jerry_value_t ret_val = jerry_create_number (result); + + return ret_val; +} + + +// init function for the module +jerry_value_t Init_my_api() +{ + + jerry_value_t object = jerry_create_object(); + + + // set an external function as a property to the module object + jerry_value_t bar_name = jerry_create_string ((const jerry_char_t*)"bar"); + jerry_value_t bar_func = jerry_create_external_function (bar_handler); + jerry_value_t bar_ret = jerry_set_property (object, bar_name, bar_func); + jerry_release_value (bar_name); + jerry_release_value (bar_func); + jerry_release_value (bar_ret); + + + // set an external function as a property to the module object + jerry_value_t foo_name = jerry_create_string ((const jerry_char_t*)"foo"); + jerry_value_t foo_func = jerry_create_external_function (foo_handler); + jerry_value_t foo_ret = jerry_set_property (object, foo_name, foo_func); + jerry_release_value (foo_name); + jerry_release_value (foo_func); + jerry_release_value (foo_ret); + + + // set an enum constant as a property to the module object + jerry_property_descriptor_t A_prop_desc; + jerry_init_property_descriptor_fields (&A_prop_desc); + A_prop_desc.is_value_defined = true; + A_prop_desc.value = jerry_create_number (A); + jerry_value_t A_name = jerry_create_string ((const jerry_char_t *)"A"); + jerry_value_t A_ret = jerry_define_own_property (object, A_name, &A_prop_desc); + jerry_release_value (A_ret); + jerry_release_value (A_name); + jerry_free_property_descriptor_fields (&A_prop_desc); + + + // set an enum constant as a property to the module object + jerry_property_descriptor_t B_prop_desc; + jerry_init_property_descriptor_fields (&B_prop_desc); + B_prop_desc.is_value_defined = true; + B_prop_desc.value = jerry_create_number (B); + jerry_value_t B_name = jerry_create_string ((const jerry_char_t *)"B"); + jerry_value_t B_ret = jerry_define_own_property (object, B_name, &B_prop_desc); + jerry_release_value (B_ret); + jerry_release_value (B_name); + jerry_free_property_descriptor_fields (&B_prop_desc); + + + // set an enum constant as a property to the module object + jerry_property_descriptor_t C_prop_desc; + jerry_init_property_descriptor_fields (&C_prop_desc); + C_prop_desc.is_value_defined = true; + C_prop_desc.value = jerry_create_number (C); + jerry_value_t C_name = jerry_create_string ((const jerry_char_t *)"C"); + jerry_value_t C_ret = jerry_define_own_property (object, C_name, &C_prop_desc); + jerry_release_value (C_ret); + jerry_release_value (C_name); + jerry_free_property_descriptor_fields (&C_prop_desc); + + + jerry_value_t N_js = jerry_create_number (N); + + + // set a global constant or a macro as a property to the module object + jerry_property_descriptor_t N_prop_desc; + jerry_init_property_descriptor_fields (&N_prop_desc); + N_prop_desc.is_value_defined = true; + N_prop_desc.value = N_js; + jerry_value_t N_prop_name = jerry_create_string ((const jerry_char_t *)"N"); + jerry_value_t N_return_value = jerry_define_own_property (object, N_prop_name, &N_prop_desc); + jerry_release_value (N_return_value); + jerry_release_value (N_prop_name); + jerry_free_property_descriptor_fields (&N_prop_desc); + + return object; +} +``` diff --git a/docs/devs/IoT.js-Package-(outdated).md b/docs/devs/IoT.js-Package-(outdated).md index 0a5d944b56..d228e262cb 100644 --- a/docs/devs/IoT.js-Package-(outdated).md +++ b/docs/devs/IoT.js-Package-(outdated).md @@ -88,7 +88,7 @@ IoT.js is released under Apache 2.0 license, [this page](../License.md). We assu 2) If it has a WiFi the download directly from the registry * But to make this work, we need to develop a small shell program with iotjs. * This can be done with built-in module downloader, we need to develop this. - * Issue [#75](https://github.com/Samsung/iotjs/issues/75) to track + * Issue [#75](https://github.com/jerryscript-project/iotjs/issues/75) to track 3) If your IoT is very small and even has no writable file system * Package modules should be built-in to IoT.js at compile time. diff --git a/docs/devs/Native-Module-vs-JS-Module.md b/docs/devs/Native-Module-vs-JS-Module.md new file mode 100644 index 0000000000..1fbd5c300a --- /dev/null +++ b/docs/devs/Native-Module-vs-JS-Module.md @@ -0,0 +1,29 @@ +# Native Module vs JS Module + +This document provides a basic guide on when to write a builtin module in Javascript instead of C. + +## What are Native module and Javascipt module? + +Native module is mainly aimed to get a direct access to low-level API of the operation system and is written in C code. While, Javascript module mainly exists as a bridge between native module and users. And, in some situations, it also includes handy functions and handles errors for API coverage. + +## When to write JS module + +In many cases, a well-written native code could prove better performance than the JavaScript equivalent. So, a feature, where computational performance is important, is recommended to be written in native module. However, that doesn't mean that every module needs be written in C only. Because there are many cases where the regular Javascript code is useful. Here are a few ground rules as a guide on when to write Javascript module. + +1. Support Node.js API usages + + One of IoT.js purposes is to support users who get used to Node.JS api as much as possible. So the builtin basic APIs should be implemented based on this purpose. A module in Node.Js generally consists a pair of native module and Javascript module. Even though there might be some optimization points on them, leave the pairs to facilitate future maintainance. + +2. Use Javascript module in the case where we can implement a feature more efficiently. + + The `efficiently` implies effciency in terms of performance, memory, implementation time, and so on. If a certain feature could be easily and rapidly implemented in Javascript but no big difference on performance or memory compared with native module, write it in javascript module. The following includes such a case but not limited to: Type conversion, basic mathematical operations, simple functionality and so on. + +3. Avoid 'Reinventing the wheel' + + In case that a well-peformed feature already exists in builtin modules, it's basically not allowed to wipe it out to native module since it's unnecessary. + +## Argument Validation & Type Conversion + +For avoiding security issue, argument validation must be handled in native module. However, native module should not take a role to convert the given type for extending API coverage. It should be done in Javascript module. + + e.g) In case of `new Buffer(str[, encoding])`, native module has a responsiblity to validate if the type of the first argument is `string`. However, in user perspective, giving `Number` as the first argument also works since Javascript module appropriately handles the given type to pass it over to the corresponding native module. diff --git a/docs/devs/Optimization-Tips.md b/docs/devs/Optimization-Tips.md index 45277c50cf..85eedddac3 100644 --- a/docs/devs/Optimization-Tips.md +++ b/docs/devs/Optimization-Tips.md @@ -1,6 +1,3 @@ -Optimization Tips -================= - ## Tracing JerryScript heap usage Adding below arguments when building and running IoT.js will show you the JerryScript memory status. @@ -46,3 +43,9 @@ You can make your compiler to place the JerryScript heap in specific section by jmem_heap_t jerry_global_heap __attribute__ ((aligned (JMEM_ALIGNMENT))) JERRY_GLOBAL_HEAP_SECTION; ``` + +## Modify the default jerry-heap size + +By default, JerryScript uses 16 bit long (8 byte aligned) pointers, that is why the maximum addressable area (on the JerryScript heap) is 512 KB. Of course, these compressed pointers can be extended to 32 bit to cover the entire address space of a 32 bit system. + +You can modify the default JerryScript heap size by using the `--jerry-heaplimit` argument when building IoT.js. If that value is bigger than `512`, the JerryScript submodule is compiled with 32 bit pointer support. diff --git a/docs/devs/Test-Guidelines.md b/docs/devs/Test-Guidelines.md new file mode 100644 index 0000000000..0928cb2103 --- /dev/null +++ b/docs/devs/Test-Guidelines.md @@ -0,0 +1,62 @@ +### To write a test case + +Depend on the purpose of the test case (whether it's a positive or negative one), place it under `test/run_pass` or `test/run_fail` directory. The required external resources should be placed into `test/resources`. + +All test case files must be named in the following form `test_[_` +should match one of the JS modules name in the IoT.js. If there is a test case which can not tied to a +module (like some js features) then the `iotjs` name can be used as module name. It is important to +correctly specify the module name as the test executor relies on that information. + +1. Write a test case and place it into the proper directory. +2. List up the test case in [test/testsets.json](https://github.com/jerryscript-project/iotjs/blob/master/test/testsets.json), and set attributes (timeout, skip, ...) on the test case if it needs. + +#### Test set descriptor +* [`test/testsets.json`](https://github.com/jerryscript-project/iotjs/blob/master/test/testsets.json) + +``` +{ + "directory": [ + { "name": "filename", + "skip": ["all"], + "reason": "reason of skipping", + "timeout": seconds, + "expected-failure": true, + "required-modules": ["my_module"], + "required-features": ["es-262-feature"] + }, + ... + ], + ... +} +``` + + - _directory_: group of tests + - _name_: filename = testname + - _skip_: platform where the test must be skipped. ["all", "darwin", "linux", "nuttx", "tizen", "tizenrt"] **(optional)** + - _reason_: it belongs to skip property, reason of skipping. **(optional)** + - _timeout_: timeout in seconds **(optional)** + - _expected-failure_: identifies the "must fail" testcases. Still catches segfaults, IOTJS_ASSERT and JERRY_ASSERT. Default: false [true, false] **(optional)** + + +### How to Test + +When you build ``iotjs`` binary successfully, you can run test runner with this binary. + +```bash +tools/testrunner.py /path/to/iotjs +``` + +#### Set test options + +Some basic options are provided. + +Existing test options are listed as follows; +``` +-h, --help show this help message and exit +--quiet show or hide the output of the tests +--skip-modules list module list to skip test of specific modules +--testsets TESTSETS JSON file to extend or override the default testsets +--timeout TIMEOUT default timeout for the tests in seconds +--valgrind check tests with Valgrind +--coverage measure JavaScript coverage +``` diff --git a/docs/devs/Use-JerryScript-Debugger.md b/docs/devs/Use-JerryScript-Debugger.md index 2af131fbda..b4fd6b12af 100644 --- a/docs/devs/Use-JerryScript-Debugger.md +++ b/docs/devs/Use-JerryScript-Debugger.md @@ -9,15 +9,45 @@ To enable the debugger support under IoT.js, the `--jerry-debugger` option should be passed to the `tools/build.py`. The server part of the debugger is intergrated into the binary of IoT.js. -If you want to specify the port number of the debugger-server (default: 5001), -you can do so with the `--jerry-debugger-port=` option. - ### Usage To start the debugger-server: ` --start-debug-server test.js` -Two clients are included, a [python](https://github.com/jerryscript-project/jerryscript/blob/master/jerry-debugger/jerry-client-ws.py) -and an [HTML](https://github.com/jerryscript-project/jerryscript/blob/master/jerry-debugger/jerry-client-ws.html) variant, they can be found under `deps/jerry/jerry-debugger/`. +It is important to note that optional parameters (such as `--debugger-wait-source` or +`--debugger-port `) should be specified after `--start-debug-server` in order to work properly. + +#### Sending source to the debugger remotely + +The `--debugger-wait-source` makes the client wait until the source files are sent by the debugger-client. +The file argument is ignored in this case, therefore doesn't need to be specified. IoT.js is also capable of resetting the context, +thus, there's no need to restart the environment if the remote source is changed. +**Important note**: Remote sources must be sent in correct order! IoT.js compiles them in the order they are received, so file(s) used with `require` should be sent first, and the file(s) using them after. + +#### Select Channel and Protocol + +There are two available extension-provided channels, websocket and rawpacket, and two protocols, tcp and serial. Each initializes the debugger and blocks until a client connects. If you want to specify the debugger channel (default: websocket) or protocol (default: tcp) over the communication you can do with the `--debug-channel [websocket|rawpacket]` and `--debug-protocol [tcp|serial]` options: + +` --start-debug-server --debugger-channel rawpacket --debug-protocol tcp test.js` + +#### Setting the debugger port + +If you want to specify the port number of the debugger-server with tcp connection (default: 5001), +you can do so with the `--debugger-port ` option: + +` --start-debug-server --debugger-port 8080 test.js` + +#### Configure the serial port + +If you want to configure parameters for serial port (default: /dev/ttyS0,115200,8,N,1), you can do with `--debug-serial-config CONFIG` option: + +` --start-debug-server --debug-channel rawpacket --debug-protocol serial --debug-serial-config "/dev/ttyUSB0,115200,8,N,1" test.js` + + +#### Available Clients + +* [JerryScript console debugger client](https://github.com/jerryscript-project/jerryscript/blob/master/jerry-debugger/jerry-client-ws.py) +* [Iot.js Code](https://github.com/jerryscript-project/iotjscode) +* [Jerryscript debugger Chrome webtool](https://github.com/jerryscript-project/jerryscript-debugger-ts) -*Note*: When snapshot support is enabled, you won't be able to examine js-modules +**Note**: When snapshot support is enabled, you won't be able to examine js-modules that are loaded from snapshots. diff --git a/docs/devs/Writing-New-Builtin-Module.md b/docs/devs/Writing-New-Builtin-Module.md deleted file mode 100644 index 27e7adea59..0000000000 --- a/docs/devs/Writing-New-Builtin-Module.md +++ /dev/null @@ -1,177 +0,0 @@ -Writing New Builtin Module -========================== - -This document provides a guide on how to write a builtin module for IoT.js. - -Contents: - -* Writing Builtin JavaScript Module -* Writing Native Module Builtin - - Using native module in JavaScript module - - Registering native module - - Native handler - * Arguments and Return - * Wrapping native object with JS object - * Callback - -You can see more information on the [Optimization Tips](Optimization-Tips.md) page. - -It will be easier to write a new IoT.js module if you have background on: - -- [Node.js module](https://nodejs.org/api/modules.html) (for writing IoT.js JavaScript module) -- [Node.js native addon](https://nodejs.org/api/addons.html) (for writing IoT.js native module builtin) - -## Writing Builtin JavaScript Module - -Builtin JavaScript module can be written in the same way as writing [Node.js module](https://nodejs.org/api/modules.html). JavaScript file should be located in `src/js/` directory, and you should notify to our build script that your module should be included in one of following ways: - -* Use `./tools/build.py --iotjs-include-module mymodule` when building -* Add your module in `build.config` file - -Your new module will look like below: - -src/js/mymodule.js: -```javascript -module.exports = { - foo: function() { console.log("OK"); }, - bar: 123 -} -``` - -user.js: -```javascript -var mymodule = require('mymodule'); -mymodule.foo(); // prints "OK" -console.log(mymodule.bar); // prints "123" -``` - -and execute: -```sh -$ ./tools/build.py -$ ${PATH_TO}/iotjs user.js -OK -123 -``` - -## Writing Native Module Builtin - -You can implement some part of the builtin module in C, to enhance performance and to fully exploit the H/W functionality, etc. It has similar concept with [Node.js native addon](https://nodejs.org/api/addons.html), but we have different set of APIs. Node.js uses its own binding layer with v8 API, but we use [our own binding layer](../../src/iotjs_binding.h) which wraps [JerryScript API](https://github.com/jerryscript-project/JerryScript/blob/master/jerry-core/jerryscript.h). You can see `src/iotjs_binding.*` files to find more APIs to communicate with JS-side values from native-side. - -For simple explanation, `console` module will be used as an example. - -### Using native module in JavaScript module - -Logging to console needs native functionality, so `console` JavaScript module in `src/js/console.js` passes its arguments into native handler like: - -```javascript -var consoleBuiltin = process.binding(process.binding.console); -... -Console.prototype.log = consoleBuiltin.stdout(util.format.apply(this, arguments) + '\n'); -``` - -### Registering native module - -According to the code above, `process.binding.console` should be defined before evaluating JavaScript code. IoT.js source code can automatically register native module if some functions are implemented as expected. First you should register your new module into `MODULE_LIST` macro in `src/iotjs_module.h`: -```c -#define MAP_MODULE_LIST(F) \ - E(F, BUFFER, Buffer, buffer) \ - E(F, CONSOLE, Console, console) \ - E(F, CONSTANTS, Constants, constants) \ - ... -``` - -Then `iotjs_jval_t Init##ModuleName()` function will be called automatically when registering native module. We already have its implementation in `src/module/iotjs_module_console.c`: -```c -iotjs_jval_t InitConsole() { - iotjs_jval_t console = iotjs_jval_create_object(); - - iotjs_jval_set_method(&console, "stdout", Stdout); - iotjs_jval_set_method(&console, "stderr", Stderr); - - return console; -} -``` -The return value of initializer function (in this case, `iotjs_jval_t console`,) will be passed to JS-side, as a return value of calling `process.binding(process.binding.modulename)`. Calling `iotjs_jval_create_object()` will create a JavaScript object in c code. - -And you might want to define some functions and properties to the newly created object. `iotjs_jval_set_method()` will register a native handler as a JavaScript function property. (That's how we was able to call `consoleBuiltin.stdout()` in JavaScript.) And `iotjs_jval_set_property_*()` will define a non-function property into object. You can find the example of registering a constant value as a JavaScript property in `src/module/iotjs_module_constants.c`. - -### Native handler - -Native handler reads arguments from JavaScript, executes native operations, and returns the final value to JavaScript. - -#### Arguments and Return - -Let's see an example in `src/module/iotjs_module_console.c`: - -```c -JHANDLER_FUNCTION(Stdout) { - JHANDLER_CHECK_ARGS(1, string); - - iotjs_string_t msg = JHANDLER_GET_ARG(0, string); - fprintf(stdout, "%s", iotjs_string_data(&msg)); - iotjs_string_destroy(&msg); -} -``` - -Using `JHANDLER_GET_ARG(index, type)` macro inside `JHANDLER_FUNCTION()` will read JS-side argument. Since JavaScript values can have dynamic types, you must check if argument has valid type with `JHANDLER_CHECK_ARGS(number_of_arguments, type1, type2, type3, ...)` macro, which throws JavaScript TypeError when given condition is not satisfied. - -Calling `void iotjs_jhandler_return_*()` function inside `JHANDLER_FUNCTION()` will return value into JS-side. `undefined` will be returned if you didn't explicitly returned something, like normal JavaScript function does. Console methods doesn't have to return values, but you can easily find more examples from other modules. - -#### Wrapping native object with JS object - -`console` module is *state-free* module, i.e., console module implementation doesn't have to hold any values with it. It just passes value and that's all it does. - -However, there are many cases that module should maintain its state. Maintaining the state in JS-side would be simple. But maintaining values in native-side is not an easy problem, because native-side values should follow the lifecycle of JS-side values. Let's take `Buffer` module as an example. `Buffer` should maintain the native buffer content and its length. And the native buffer content should be deallocated when JS-side buffer variable becomes unreachable. - -There's `iotjs_jobjectwrap_t` struct for that purpose. if you create a new `iotjs_jobjectwrap_t` struct with JavaScript object as its argument and free handler, the registered free handler will be automatically called when its corresponding JavaScript object becomes unreachable. `Buffer` module also exploits this feature. - -```c -// This wrapper refer javascript object but never increase reference count -// If the object is freed by GC, then this wrapper instance will be also freed. -typedef struct { - iotjs_jval_t jobject; -} iotjs_jobjectwrap_t; - -typedef struct { - iotjs_jobjectwrap_t jobjectwrap; - char* buffer; - size_t length; -} iotjs_bufferwrap_t; - -static void iotjs_bufferwrap_destroy(iotjs_bufferwrap_t* bufferwrap); -IOTJS_DEFINE_NATIVE_HANDLE_INFO(bufferwrap); - -iotjs_bufferwrap_t* iotjs_bufferwrap_create(const iotjs_jval_t* jbuiltin, - size_t length) { - iotjs_bufferwrap_t* bufferwrap = IOTJS_ALLOC(iotjs_bufferwrap_t); - iotjs_jobjectwrap_initialize(&_this->jobjectwrap, - jbuiltin, - &bufferwrap_native_info); /* Automatically called */ - ... -} - -void iotjs_bufferwrap_destroy(iotjs_bufferwrap_t* bufferwrap) { - ... - iotjs_jobjectwrap_destroy(&_this->jobjectwrap); - IOTJS_RELEASE(bufferwrap); -} -``` - -You can use this code like below: - -```c -const iotjs_jval_t* jbuiltin = /*...*/; -iotjs_bufferwrap_t* buffer_wrap = iotjs_bufferwrap_create(jbuiltin, length); -// Now `jbuiltin` object can be used in JS-side, -// and when it becomes unreachable, `iotjs_bufferwrap_destroy` will be called. -``` - -#### Callback - -Sometimes native handler should call JavaScript function directly. For general function calls (inside current tick), you can use `iotjs_jhelper_call()` function to call JavaScript function from native-side. - -And for asynchronous callbacks, after `libtuv` calls your native function, if you want to call JS-side callback you should use `iotjs_make_callback()`. It will not only call the callback function, but also handle the exception, and process the next tick(i.e. it will call `iotjs_process_next_tick()`). - -For asynchronous callbacks, you must consider the lifetime of JS-side callback objects. The lifetime of JS-side callback object should be extended until the native-side callback is really called. You can use `iotjs_reqwrap_t` and `iotjs_handlewrap_t` to achieve this. - -(Work In Progress) diff --git a/docs/devs/Writing-New-Module.md b/docs/devs/Writing-New-Module.md new file mode 100644 index 0000000000..08297accba --- /dev/null +++ b/docs/devs/Writing-New-Module.md @@ -0,0 +1,611 @@ +# How to write a new module + +This document provides a guide on how to write a module for IoT.js. + +Contents +* Writing JavaScript Module +* Writing Native Module + * Platform dependent native parts + * Native handler + * Arguments and Return + * Wrapping native object with JS object + * Callback +* Writing "Mixed" Module + * Using native module in JavaScript module +* Advanced usage + * Module specific CMake file + * Writing Dynamically loadable modules (N-API) +* Module structure generator + +See also: +* [Inside IoT.js](Inside-IoT.js.md) +* [Native Module vs. JS module](Native-Module-vs-JS-Module.md) +* [Optimization Tips](Optimization-Tips.md) +* [Developer Tutorial](Developer-Tutorial.md) + +## Writing JavaScript Module + +JavaScript module can be written in the same way as writing [Node.js module](https://nodejs.org/api/modules.html). JavaScript file should be located anywhere on your filesystem. + +* Use `./tools/build.py --external-modules=my-module` when building +* Enable your module in a profile or as an additional CMake parameter + +**Important:** the name of the module must be in lowercase. It is not allowed to use uppercase characters. + +Your new module will look like below: + +my-module/js/mymodule.js: +```javascript +module.exports = { + foo: function() { console.log("OK"); }, + bar: 123 +} +``` + +my-module/modules.json: +```json +{ + "modules": { + "mymodule": { + "js_file": "js/mymodule.js", + "require": ["buffer", "console"] + } + } +} +``` + +user.js: +```javascript +var mymodule = require('mymodule'); +mymodule.foo(); // prints "OK" +console.log(mymodule.bar); // prints "123" +``` + +and execute: +```sh +$ ./tools/build.py --external-modules=./my-module --cmake-param=-DENABLE_MODULE_MYMODULE=ON +$ ${PATH_TO}/iotjs user.js +OK +123 +``` + +**Note**: `--cmake-param=-DENABLE_MODULE_MYMODULE=ON` option must be used in case of an +external module, because the default profile enables only the basic and core modules. + + +### ENABLE_MODULE_[NAME] + +An uppercase `ENABLE_MODULE_[NAME]` CMake variable will be generated for every module, +where `NAME` is the name of the module in the `modules.json`. To enable or disable a +module by setting the corresponding `ENABLE_MODULE_[NAME]` to ON or OFF. It will override +the defult settings of the profile. + +### Profile + +The purpose of the "profile" is to describe the default settings of enabled modules for +the build. A profile file is a list of `ENABLE_MODULE_[NAME]` macros. Those module whos +`ENABLE_MODULE_[NAME]` macro is not listed will be disabled by defult. + +my-module/mymodule.profile: +``` +ENABLE_MODULE_IOTJS_BASIC_MODULES +ENABLE_MODULE_IOTJS_CORE_MODULES +ENABLE_MODULE_MYMODULE +``` + +Execute: +```bash +./tools/build.py --external-modules=./my-module --profile=my-module/mymodule.profile +``` + + +## Writing Native Module + +You can implement some part of the builtin module in C, to enhance performance and to fully exploit the H/W functionality, etc. It has similar concept with [Node.js native addon](https://nodejs.org/api/addons.html), but we have different set of APIs. Node.js uses its own binding layer with v8 API, but we use [our own binding layer](../../src/iotjs_binding.h) which wraps [JerryScript API](https://github.com/jerryscript-project/jerryscript/blob/master/jerry-core/jerryscript.h). You can see `src/iotjs_binding.*` files to find more APIs to communicate with JS-side values from native-side of you can call JerryScript API functions directly. + +* For native modules you must define an `init` function that provides the JS object that represents your module. +* You can define multiple native files. +* Directory of your module will be added to the include path. +* Use `./tools/build.py --external-modules=my-module` when building. +* Enable your module in a profile or as an additional CMake parameter. + +Your new module will look like below: + +my-module/my_module.c: +```javascript +#include "iotjs_def.h" + +jerry_value_t InitMyNativeModule() { + jerry_value_t mymodule = jerry_create_object(); + iotjs_jval_set_property_string_raw(mymodule, "message", "Hello world!"); + return mymodule; +} +``` + +my-module/modules.json: +```json +{ + "modules": { + "mymodule": { + "native_files": ["my_module.c"], + "init": "InitMyNativeModule" + } + } +} +``` + +user.js: +```javascript +var mymodule = require('mymodule'); +console.log(mymodule.message); // prints "Hello world!" +``` + +and execute: +```sh +$ ./tools/build.py --external-modules=./my-module --cmake-param=-DENABLE_MODULE_MYMODULE=ON +$ ${PATH_TO}/iotjs user.js +Hello world! +``` + +### Platform dependent native parts + +You can define the platform dependent low level parts in the `modules.json`. + +Structure of the directory of the custom module: +``` +my_module + |-- linux + |-- my_module_platform_impl.c + |-- nuttx + |-- my_module_platform_impl.c + |-- tizenrt + |-- my_module_platform_impl.c + |-- other + |-- my_module_platform_impl.c + |-- modules.json + |-- my_module.h + |-- my_module.c +``` + +modules.json: +```json +{ + "modules": { + "mymodule": { + "platforms": { + "linux": { + "native_files": ["linux/my_module_platform_impl.c"] + }, + "nuttx": { + "native_files": ["nuttx/my_module_platform_impl.c"] + }, + "tizenrt": { + "native_files": ["tizenrt/my_module_platform_impl.c"] + }, + "undefined": { + "native_files": ["other/my_module_platform_impl.c"] + } + }, + "native_files": ["my_module.c"], + "init": "InitMyModule" + } + } +} +``` + +**Note**: Undefined platform means a general implementation. If the module does not support your platform then it will use the `undefined` platform implementation. + +### Library dependency + +It is possible that the external module depends/requires an already compiled third-party shared object or static library. +Such libraries can be specified in the `modules.json` file so they will be linked when the IoT.js module is used. +To specify third-party libraries the `external_libs` key should be used in the module specification. + +For example in the `modules.json`: + +```json +{ + "modules": { + "mymodule": { + "platforms": { + "linux": { + "native_files": ["linux/my_module_platform_impl.c"], + "external_libs": ["curl"] + } + }, + "native_files": ["my_module.c"], + "external_libs": ["lib_shared_on_all_platforms_if_it_truly_exists"], + "init": "InitMyNativeModule" + } + } +} +``` + +The `external_libs` key can be specified on the module level or for each platform also. + +### Native handler + +Native handler reads arguments from JavaScript, executes native operations, and returns the final value to JavaScript. + +#### Arguments and Return + +Let's see an example in `src/module/iotjs_module_console.c`: + +```c +JS_FUNCTION(Stdout) { + DJS_CHECK_ARGS(1, string); + + iotjs_string_t msg = JS_GET_ARG(0, string); + fprintf(stdout, "%s", iotjs_string_data(&msg)); + iotjs_string_destroy(&msg); + + return jerry_create_undefined(); +} +``` + +Using `JS_GET_ARG(index, type)` macro inside `JS_FUNCTION()` will read JS-side argument. Since JavaScript values can have dynamic types, you must check if argument has valid type with `DJS_CHECK_ARGS(number_of_arguments, type1, type2, type3, ...)` macro, which throws JavaScript TypeError when given condition is not satisfied. + +`JS_FUNCTION()` must return with an `jerry_value_t` into JS-side. + +#### Wrapping native object with JS object + +`console` module is *state-free* module, i.e., console module implementation doesn't have to hold any values with it. It just passes value and that's all it does. + +However, there are many cases that module should maintain its state. Maintaining the state in JS-side would be simple. But maintaining values in native-side is not an easy problem, because native-side values should follow the lifecycle of JS-side values. Let's take `Buffer` module as an example. `Buffer` should maintain the native buffer content and its length. And the native buffer content should be deallocated when JS-side buffer variable becomes unreachable. + +There's `iotjs_jobjectwrap_t` struct for that purpose. if you create a new `iotjs_jobjectwrap_t` struct with JavaScript object as its argument and free handler, the registered free handler will be automatically called when its corresponding JavaScript object becomes unreachable. `Buffer` module also exploits this feature. + +```c +// This wrapper refer javascript object but never increase reference count +// If the object is freed by GC, then this wrapper instance will be also freed. +typedef struct { + jerry_value_t jobject; +} iotjs_jobjectwrap_t; + +typedef struct { + iotjs_jobjectwrap_t jobjectwrap; + char* buffer; + size_t length; +} iotjs_bufferwrap_t; + +static void iotjs_bufferwrap_destroy(iotjs_bufferwrap_t* bufferwrap); +IOTJS_DEFINE_NATIVE_HANDLE_INFO(bufferwrap); + +iotjs_bufferwrap_t* iotjs_bufferwrap_create(const jerry_value_t* jbuiltin, + size_t length) { + iotjs_bufferwrap_t* bufferwrap = IOTJS_ALLOC(iotjs_bufferwrap_t); + iotjs_jobjectwrap_initialize(&_this->jobjectwrap, + jbuiltin, + &bufferwrap_native_info); /* Automatically called */ + ... +} + +void iotjs_bufferwrap_destroy(iotjs_bufferwrap_t* bufferwrap) { + ... + iotjs_jobjectwrap_destroy(&_this->jobjectwrap); + IOTJS_RELEASE(bufferwrap); +} +``` + +You can use this code like below: + +```c +const jerry_value_t* jbuiltin = /*...*/; +iotjs_bufferwrap_t* buffer_wrap = iotjs_bufferwrap_create(jbuiltin, length); +// Now `jbuiltin` object can be used in JS-side, +// and when it becomes unreachable, `iotjs_bufferwrap_destroy` will be called. +``` + +#### Callback + +Sometimes native handler should call JavaScript function directly. For general function calls (inside current tick), you can use `iotjs_jhelper_call()` function to call JavaScript function from native-side. + +And for asynchronous callbacks, after `libtuv` calls your native function, if you want to call JS-side callback you should use `iotjs_make_callback()`. It will not only call the callback function, but also handle the exception, and process the next tick(i.e. it will call `iotjs_process_next_tick()`). + +For asynchronous callbacks, you must consider the lifetime of JS-side callback objects. The lifetime of JS-side callback object should be extended until the native-side callback is really called. You can use `iotjs_reqwrap_t` and `iotjs_handlewrap_t` to achieve this. + +## Writing "Mixed" Modules + +Modules could be a combination of JS and native code. In that case the Javascript file must +export the objects of the module. In such cases the native part will be hidden. + +For simple explanation, `console` module will be used as an example. + +``` +src + |-- js + |-- console.js + |-- modules + |-- iotjs_module_console.c + |-- modules.json +``` + +modules.json +```json +{ + "modules": { + ... + "console": { + "native_files": ["modules/iotjs_module_console.c"], + "init": "InitConsole", + "js_file": "js/console.js", + "require": ["util"] + }, + ... + } +} +``` + +### Using native module in JavaScript module + +Logging to console needs native functionality, so `console` JavaScript module in `src/js/console.js` passes its arguments into native handler like: + +```javascript +Console.prototype.log = native.stdout(util.format.apply(this, arguments) + '\n'); +``` + +Where `native` is the JS object returned by the native `InitConsole` function in `iotjs_module_console.c`. + +**Note**: `native` is undefined if there is no native part of the module. + + +### Using bridge module to communicate between C and JavaScript module +Bridge module provides two interfaces for sending synchronous and asynchronous message from Javascript to the native module. The Native module simply rersponds back to the requst using a simple inteface that can create return message. Of course you can use the IoT.js and JerryScript APIs to respond directly to the request of JavaScript module, but sometimes using a simpliffied method is more efficient in providing simple functionality in a short time. + +For example, JavaScript module can request resource path synchronously, +and native module can simply return a resource path by just calling a function. + +in the bridge_sample.js of bridge_sample module +```javascript +bridge_sample.prototype.getResPath = function(){ + return this.bridge.sendSync("getResPath", ""); +}; +``` + +in the iotjs_bridge_sample.c of bridge_sample module +```c +if (strncmp(command, "getResPath", strlen("getResPath")) == 0) { + iotjs_bridge_set_return(return_message, "res/"); + return 0; +} +``` +For the complete sample code, please see the bridge_sample in samples/bridge_sample folder. + +## Advanced usage + +### Module specific CMake file + +For each module, it is possible to define one extra cmake file. +This can be done by specifying the `cmakefile` key file for +a module in the related `modules.json` file. + +For example: + +```json +{ + "modules": { + "demomod": { + ... + "cmakefile": "module.cmake" + } + } +} +``` + +This `module.cmake` is a module-specific CMake file +which will be searchd for in the module's base directory. +In this file it is possible to specify additonal dependecies, +build targets, and other things. + +However, there are a few important rules which must be followed in +the CMake file: + +* The `MODULE_DIR` and `MODULE_BINARY_DIR` will be set by + the IoT.js build system. Do NOT overwrite them in the CMake file! + +* The `MODULE_NAME` CMake variable must be set. + Example: `set(MODULE_NAME "demomod")` + +* The `add_subdirectory` call must specify the output binary dir. + Please use this template: +`add_subdirectory(${MODULE_DIR}/lib/ ${MODULE_BASE_BINARY_DIR}/${MODULE_NAME})` + where `lib/` is a subdirectory of the module directory. + +* If there is an extra library which should be used during linking, the + following template should be used: + `list(APPEND MODULE_LIBS demo)` + where `demo` is the extra module which must be linked. + Any number of modules can be appended to the `MODULE_LIBS` list variable. + +* The source files which are specified in the `modules.json` file must NOT + be specified in the CMake file. + + +An example module CMake file: +``` +set(MODULE_NAME "mymodule") + +add_subdirectory(${MODULE_DIR}/myLib/ ${MODULE_BASE_BINARY_DIR}/${MODULE_NAME}) + +list(APPEND MODULE_LIBS myLib) +``` + +To ease creation of modules which contains extra CMake files +there is a module generator as described below. + + +## Writing Dynamically loadable modules (N-API) + +IoT.js support N-API for building and loading native addons. +To create such modules the source files must be compiled into +a shared object and must have a special entry point defined. + +See also: + * [N-API in IoT.js](../api/IoT.js-API-N-API.md) + * [N-API module registration](https://nodejs.org/docs/latest-v10.x/api/n-api.html#n_api_module_registration) macro. + +N-API modules are registered in a manner similar to other modules +except that instead of using the `NODE_MODULE` macro the following +is used: + +```C +NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) +``` + +The next difference is the signature for the `Init` method. For a N-API +module it is as follows: + +```C +napi_value Init(napi_env env, napi_value exports); +``` + +The return value from `Init` is treated as the `exports` object for the module. +The `Init` method is passed an empty object via the `exports` parameter as a +convenience. If `Init` returns NULL, the parameter passed as `exports` is +exported by the module. N-API modules cannot modify the `module` object but can +specify anything as the `exports` property of the module. + +To add the method `hello` as a function so that it can be called as a method +provided by the addon: + +```C +napi_value Init(napi_env env, napi_value exports) { + napi_status status; + napi_property_descriptor desc = + {"hello", NULL, Method, NULL, NULL, NULL, napi_default, NULL}; + status = napi_define_properties(env, exports, 1, &desc); + if (status != napi_ok) return NULL; + return exports; +} +``` + +To set a function to be returned by the `require()` for the addon: + +```C +napi_value Init(napi_env env, napi_value exports) { + napi_value method; + napi_status status; + status = napi_create_function(env, "exports", NAPI_AUTO_LENGTH, Method, NULL, &method); + if (status != napi_ok) return NULL; + return method; +} +``` + +To define a class so that new instances can be created (often used with +[Object Wrap][]): + +```C +// NOTE: partial example, not all referenced code is included +napi_value Init(napi_env env, napi_value exports) { + napi_status status; + napi_property_descriptor properties[] = { + { "value", NULL, NULL, GetValue, SetValue, NULL, napi_default, NULL }, + DECLARE_NAPI_METHOD("plusOne", PlusOne), + DECLARE_NAPI_METHOD("multiply", Multiply), + }; + + napi_value cons; + status = + napi_define_class(env, "MyObject", New, NULL, 3, properties, &cons); + if (status != napi_ok) return NULL; + + status = napi_create_reference(env, cons, 1, &constructor); + if (status != napi_ok) return NULL; + + status = napi_set_named_property(env, exports, "MyObject", cons); + if (status != napi_ok) return NULL; + + return exports; +} +``` + +If the module will be loaded multiple times during the lifetime of the Node.js +process, use the `NAPI_MODULE_INIT` macro to initialize the module: + +```C +NAPI_MODULE_INIT() { + napi_value answer; + napi_status result; + + status = napi_create_int64(env, 42, &answer); + if (status != napi_ok) return NULL; + + status = napi_set_named_property(env, exports, "answer", answer); + if (status != napi_ok) return NULL; + + return exports; +} +``` + +This macro includes `NAPI_MODULE`, and declares an `Init` function with a +special name and with visibility beyond the addon. This will allow IoT.js to +initialize the module even if it is loaded multiple times. + + +## Module structure generator + +As previously shown, there are a few files required to create a module. +These files can be createad manually or by the `tools/iotjs-create-module.py` +script. + +The module generator can generate two types of modules: +* basic built-in module which is compiled into the IoT.js binary. +* shared module which can be dynamically loaded via the `require` call. + +To generate a module with the IoT.js module generator +the module template should be specified and the name of the new module. + +**Important note:** The module name must be in lowercase. + +The `template` paramter for the module creator is optional, if it is +not specified basic modules are created. + +The generated module(s) have simple examples in it which can be used +to bootstrap ones own module(s). On how to use them please see the +previous parts of this document. + +### Basic module generation + +Example basic module generation: +``` +$ python ./iotjs/tools/iotjs-create-module.py --template basic demomod +Creating module in ./demomod +loading template file: ./iotjs/tools/module_template/module.cmake +loading template file: ./iotjs/tools/module_template/modules.json +loading template file: ./iotjs/tools/module_template/js/module.js +loading template file: ./iotjs/tools/module_template/src/module.c +Module created in: /mnt/work/demomod +``` + +By default the following structure will be created by the tool: + +``` +demomod/ + |-- js + |-- module.js + |-- module.cmake + |-- modules.json + |-- src + |-- module.c +``` + +### Shared (N-API) module generation + +Example shared module generation: +``` +$ python ./iotjs/tools/iotjs-create-module.py --template shared demomod +Creating module in ./demomod +loading template file: ./iotjs/tools/module_templates/shared_module_template/CMakeLists.txt +loading template file: ./iotjs/tools/module_templates/shared_module_template/README.md +loading template file: ./iotjs/tools/module_templates/shared_module_template/js/test.js +loading template file: ./iotjs/tools/module_templates/shared_module_template/src/module_entry.c +Module created in: /mnt/work/demomod +``` + +The generated `demomod` will have a `CMakeLists.txt` file which contains +path variables to the IoT.js headers and JerryScript headers. These path +variables are absolute paths and required to the module compilation. +Please adapt the paths if required. + +Additionnally the `README.md` file contains basic instructions on +how to build and test the new module. diff --git a/docs/help/API-document-sample.md b/docs/help/API-document-sample.md deleted file mode 100644 index 8ef53fcef3..0000000000 --- a/docs/help/API-document-sample.md +++ /dev/null @@ -1,246 +0,0 @@ -## This is a sample API reference. Please use this as a guideline to write your module's API references. - -- If you have any questions about this guide, please let us know as an issue. -- `Markdown Example` is added to help understanding, and you can ignore it when writing the actual document. -- In case of `experimental` module, it's required to explicitly indicate that the features are experimental. Please put the caution below to the begining of the document. -> :exclamation: This document describes an experimental feature and considerations. Please be aware that every experimental feature may change, be broken, or be removed in the future without any notice. - -*** - -### Platform Support - -The following shows `{Your_module_name}` module APIs available for each platform. - -| | Linux
(Ubuntu) | Raspbian
(Raspberry Pi) | NuttX
(STM32F4-Discovery) | -| :---: | :---: | :---: | :---: | -| {functionName1} | O | O | O | -| {functionName2} | O | O | O | -| {functionName3} | O | O | O | - -### Contents - -- [{Your_module_name}](#your_module_name) - - [Class: {Your_class_name}](#class-your_class_name) - - [Constructor](#constructor) - - [`new {Your_class_name}([{argument_name}])`](#new-your_class_nameargument_name) - - [Properties](#properties) - - [`{your_class_name}.{property_name}`](#your_class_nameproperty_name) - - [Static Functions](#static-functions) - - [`{Your_class_name}.{your_static_function_name}([{argument_name}])`](#your_class_nameyour_static_function_nameargument_name) - - [Prototype Functions](#prototype-functions) - - [`{your_class_name}.{your_prototype_function_name}([{argument_name}])`](#your_class_nameyour_prototype_function_nameargument_name) - - [Events](#events) - - [`{your_events_name}`](#your_events_name) - - [Module Functions](#module-functions) - - [`{your_module_name}.{your_module_function_name}([{argument_name}])`](#your_module_nameyour_module_function_nameargument_name) - -# {Your_module_name} - -- Write a brief description of this module here. -- The first character of the title must start with an `uppercase letter`. - -#### Markdown Example - -``` -# Timer - -The timer module exposes a global API for scheduling functions to be called at some future period of time. -Because the timer functions are globals, there is no need to call require('timers') to use the API. -``` - -# Class: {Your_class_name} - -- Write a brief description of this class here. -- The first character of the title must start with an `uppercase letter`. -- The table of contents should be in order of `"Constructor"`, `"Properties"`, `"Protype Functions"`, and `"Events"`. -- While you are writing this description, if you need to write down module / class / function / event name, arguments, or type which you already mentioned, then enclose the keyword in single-quotation. This rule applies to other items as well. - - E.g) The given `callback` is called every `delay` milliseconds. If it's not a function, a `TypeError` will be thrown. - -## Constructor - -### `new {Your_class_name}([{argument_name}])` -* `{argument_name} <{Argument_type}> Default: {defalut_value}` - {more information} - -Notice that every API name is in a single-quote. - -#### Markdown Example - -``` -# Class: Buffer - -Buffer class is a global type with various constructors and accessors. -IoT.js provides Buffer to manipulate binary data. Currently buffer has a pure -ES5 compatible implementation, but this might be reworked to use `UInt8Array` in the future. - -## Constructor - -### `new Buffer(size)` -* `size Default: 0` - size of the new buffer - -Creates a new buffer of `size` bytes and initialize its data to zero. - -``` - -## Properties - -### `{your_class_name}.{property_name}` - -- Write a description of this property here. -- The title should be in a single quote. -- The first character of the title must start with a `lowercase letter`. - -**Example** -``` - Write a sample usage for this API if needed. -``` -#### Markdown Example -``` -## Properties - -### `buffer.length` -* `` - length of the buffer - -Returns the capacity of the buffer in bytes. Note: when -the buffer is converted to another type (e.g. `String`) the -length of the converted value might be different from -this value. - -**Example** - -```js -var Buffer = require('buffer'); - -var buffer = new Buffer([0xc8, 0x80]) -console.log(buffer.length); // prints 2 - -var str = buffer.toString(); -console.log(str.length); // prints 1 -``` - -## Static Functions - -Write a description of static functions that belongs to the current class. - -### `{Your_class_name}.{your_static_function_name}([{argument_name}])` -* `{argument_name} <{Argument_type}> Default: {defalut_value}` - {more information} - -- Write a description of this function here. -- The first character of Class in the title must start with an `Uppercase letter`. -- The other rules are the same as mentioned before. - -**Example** -``` - Write a sample usage for this API if needed. -``` - - -#### Markdown Example - -``` -## Static Functions - -### `Buffer.byteLength(str[, encoding])` -* `str ` - source string -* `encoding ` - string encoding -* Returns: `` - byte length of source string - -Returns the byte length of a buffer representing the value -of the `string` argument encoded with `encoding`. The -effect is the same as: - -```js -return new Buffer(str, encoding).length; -``` - -## Prototype Functions - -Write a description of prototype functions that belongs to the current class. - -### `{your_class_name}.{your_prototype_function_name}([{argument_name}])` -* `{argument_name} <{Argument_type}> Default: {defalut_value}` - {more information} - -- Write a description of this function here. -- The first character of Class in the title must start with a `lowercase letter`. -- The other rules are the same as mentioned before. - -**Example** -``` - Write a sample usage for this API if needed. -``` - -#### Markdown Example - -``` -### `emitter.addListener(event, listener)` -### `emitter.on(event, listener)` -* `event ` -* `listener ` - * `...args ` -* Returns: `` - -Adds `listener` to the end of list of event listeners for `event`. - -**Example** - -```js -var EventEmitter = require('events').EventEmitter; -var emitter = new EventEmitter(); - -emitter.addListener('event', function() { - console.log('emit event'); -}); -``` - -## Events - -### `{your_events_name}` -* `{callback_name} <{callback_function_argument}>` - * `{argument1} <{argument2_type}>` - {more information} - -- Write a description of this here. -- In case of Event, the name of Class that this event belongs to, is not prepended in the title. -- The other rules are the same as mentioned before. - -#### Markdown Example - -``` -## Events - -### `'lookup'` -* `callback ` - * `err | Null` - Optionally, write a description for each argument. - * `address ` - * `family | Null` -``` - - - Notice that the `err | Null` above is started with `2 spaces` indentation since it's given to `callback` as parameters, not `lookup` event. - -# Module Functions - -- `Module functions` are what you can directly invoke without an instance of a certain Class. E.g) net.connect. -- Write a description of this here. - -## `{your_module_name}.{your_module_function_name}([{argument_name}])` -* `{argument_name} <{Argument_type}> Default: {defalut_value}` - {more information} - -- Write a description of this function here. -- The first character of Class in the title must start with a `lowercase letter`. -- The other rules are the same as mentioned before. - -### Example -``` - Write a sample usage for this API if needed. -``` - -#### Markdown Example -``` -### `gpio.open(configuration[, callback])` -* `configuration ` - * `pin ` - pin number to configure, mandatory configuration - * `direction Default: GPIO.DIRECTION.OUT` - direction of the pin -* `callback ` -* Returns: `` -``` -- Notice that the `pin ` above is started with `2 spaces` indentation since it's a property inside `configuration`. -ss \ No newline at end of file diff --git a/docs/help/Developer's-Guide.md b/docs/help/Developer's-Guide.md deleted file mode 100644 index fe8d950e46..0000000000 --- a/docs/help/Developer's-Guide.md +++ /dev/null @@ -1,3 +0,0 @@ - - [Getting Started](Getting-Started.md) - - [Developer Tutorial](Developer-Tutorial.md) - - [IoT.js API Reference](../api/IoT.js-API-reference.md) \ No newline at end of file diff --git a/docs/help/Getting-Started.md b/docs/help/Getting-Started.md deleted file mode 100644 index c35a5f585a..0000000000 --- a/docs/help/Getting-Started.md +++ /dev/null @@ -1,94 +0,0 @@ -### Overview -IoT.js is built based on **JerryScript** (lightweight JavaScript engine) and **libtuv** for asynchronous I/O event handling. - -#### Source repositories -* IoT.js: https://github.com/Samsung/iotjs.git -* JerryScript: https://github.com/jerryscript-project/jerryscript.git -* libtuv: https://github.com/Samsung/libtuv.git - -### Build script -There is a script to help you build IoT.js called "[build.py](../../tools/build.py)" in source repository. - -### Supported platforms -Current supported platforms are **Linux and NuttX** - -* [Build for Linux](../build/Build-for-Linux.md): Ubuntu 14.04 is used as a base platform. -* [Build for NuttX](../build/Build-for-NuttX.md) -* [Build for Raspberry Pi 2](../build/Build-for-RPi2.md) - -##### Platforms to support -* OSX 10.10 as development host -* [Artik 1 =>](https://www.artik.io/hardware/artik-1) as target board - -##### H/W boards -* Current supporting - * STM32F4-Discovery + BB - * Raspberry Pi 2 -* Plan to support - * Samsung Artik 1 - * STM32F429-Discovery - * STM32F411-Nucleo - * Intel Edison - * (and your contributions including above plans) - -We will support the correct behavior of APIs for above environments. However, since IoT.js is targeting various kind IoT devices and platforms, single implementation cannot be the best practice for every environments. Therefore embedders should be in charge of optimization for their own environments. For more details on optimization, see the [Optimization Tips](../devs/Optimization-Tips.md) page. - -### For Developers - -#### How to Test - -When you build ``iotjs`` binary successfully, you can run test driver with this binary. - -```bash -/path/to/iotjs tools/check_test.js -``` - -##### Set test options - -Some basic options are provided. - -Existing test options are listed as follows; -``` -start-from -quiet=yes|no (default is yes) -output-file -skip-module -output-coverage=yes|no (default is no) -experimental=yes|no (default is no) -``` - -To give options, please use two dashes '--' **once** before the option name as described in the following sections. - -Options that may need explanations. -* start-from: a test case file name where the driver starts. -* quiet: a flag that indicates if the driver suppresses console outputs of test case. -* output-file: a file name where the driver leaves output. -* skip-module: a module list to skip test of specific modules. -* output-coverage: a flag that indicates wether coverage data should be written to disk -* experimental: a flag that indicates if tests for experimental are needed - -##### Options example - -```bash -build/x86_64-linux/debug/bin/iotjs tools/check_test.js -- start-from=test_console.js quiet=no -``` - -##### To write a test case - -Depend on the purpose of the test case (whether it's a positive or negative one), place it under `test/run_pass` or `test/run_fail` directory. The required external resources should be placed into `test/resources`. - -All test case files must be named in the following form `test_[_` -should match one of the JS modules name in the IoT.js. If there is a test case which can not tied to a -module (like some js features) then the `iotjs` name can be used as module name. It is important to -correctly specify the module name as the test executor relies on that information. - -1. Write a test case and place it into the proper directory. -2. List up the test case in [test/testsets.json](../../test/testsets.json), and set attributes (timeout, skip, ...) on the test case if it needs. - -#### Advanced Topics -You can refer to [Writing new IoT.js builtin module](../devs/Writing-New-Builtin-Module.md) and [Optimization Tips](../devs/Optimization-Tips.md) pages for detailed information. - -### When something goes wrong -Please read the [Logging IoT.js execution](../devs/Logging-IoT.js-execution.md) page how to display and add log messages while developing. - -### [IoT.js API Reference](../api/IoT.js-API-reference.md) diff --git a/docs/help/Getting-involved.md b/docs/help/Getting-involved.md deleted file mode 100644 index 18f2d390ac..0000000000 --- a/docs/help/Getting-involved.md +++ /dev/null @@ -1,12 +0,0 @@ -To contribute to the IoT.js Project (such as reporting bugs and submitting patches): -* Follow the [Development Process](Development-Process.md) and [GitHub contributor guidelines](https://guides.github.com/activities/contributing-to-open-source/). -* Add the [IoT.js DCO](IoT.js-Developer's-Certificate-of-Origin-1.0.md) signoff to each commit message during development. -* Add the [License](../License.md) if you introduce any new source code or script files - -### [Community Guideline](Community-Guidelines.md) -### [IoT.js Developer's Certificate of Origin 1.0](IoT.js-Developer's-Certificate-of-Origin-1.0.md) -### [Coding Style Guideline](Coding-Style-Guideline.md) -### [Inside IoT.js](../devs/Inside-IoT.js.md) -### [Development Process](Development-Process.md) -### [Patch Submission Process](Patch-Submission-Process.md) -### [Governance](Governance.md) \ No newline at end of file diff --git a/docs/targets/nuttx/stm32f4dis/IoT.js-API-Stm32f4dis.md b/docs/targets/nuttx/stm32f4dis/IoT.js-API-Stm32f4dis.md index 8bb35f678b..30dd71e0a0 100644 --- a/docs/targets/nuttx/stm32f4dis/IoT.js-API-Stm32f4dis.md +++ b/docs/targets/nuttx/stm32f4dis/IoT.js-API-Stm32f4dis.md @@ -171,7 +171,21 @@ In order to use the I2C on stm32f4-discovery board, you must use proper pins. Currently only I2C1 is supported. The following table shows the I2C pin map: + | I2C Pin Name | GPIO Name | | :--- | :---: | | I2C1_SCL | PB8 | | I2C1_SDA | PB7 | + + +## SPI Bus Information + +The following table shows currently supported SPI pin number list. +Currently only SPI1 is supported. + +| SPI Pin Name | GPIO Name | +| :--- | :---: | +| SPI1_SCK | PA5 | +| SPI1_MISO | PA6 | +| SPI1_MOSI | PA7 | +| SPI1_NSS | PA15 | \ No newline at end of file diff --git a/docs/targets/nuttx/stm32f4dis/README.md b/docs/targets/nuttx/stm32f4dis/README.md deleted file mode 100644 index b52bc7f100..0000000000 --- a/docs/targets/nuttx/stm32f4dis/README.md +++ /dev/null @@ -1,167 +0,0 @@ -### About - -This directory contains files to run IoT.js on -[STM32F4-Discovery board](http://www.st.com/content/st_com/en/products/evaluation-tools/product-evaluation-tools/mcu-eval-tools/stm32-mcu-eval-tools/stm32-mcu-discovery-kits/stm32f4discovery.html) with [NuttX](http://nuttx.org/) - -### How to build - -#### 1. Set up the build environment for STM32F4-Discovery board - -Clone IoT.js and NuttX into iotjs-nuttx directory - -```bash -$ mkdir iotjs-nuttx -$ cd iotjs-nuttx -$ git clone https://github.com/Samsung/iotjs.git -$ git clone https://bitbucket.org/nuttx/nuttx.git --branch nuttx-7.19 -$ git clone https://bitbucket.org/nuttx/apps.git --branch nuttx-7.19 -$ git clone https://github.com/texane/stlink.git -``` - -Note that we only support the specified git tag from nuttx repository - -The following directory structure is created after these commands - -```bash -iotjs-nuttx - + apps - + iotjs - | + config - | + nuttx - | + stm32f4dis - + nuttx - + stlink -``` - -#### 2. Add IoT.js as a builtin application for NuttX - -```bash -$ cd apps/system -$ mkdir iotjs -$ cp ../../iotjs/config/nuttx/stm32f4dis/app/* ./iotjs/ -``` - -#### 3. Configure NuttX - -```bash -# assuming you are in iotjs-nuttx folder -$ cd nuttx/tools - -# configure NuttX USB console shell -$ ./configure.sh stm32f4discovery/usbnsh -``` - -Now you can configure nuttx like either of below. For convenience, we provide built-in configure file for you. (This configure file is equipped with modules specified as `always`. For `optional` modules, you might follow instructions below.) -```bash -$ cd .. -$ cp ../iotjs/config/nuttx/stm32f4dis/.config.default .config -``` - -Or if you want to configure yourself, you can follow guide below. -```bash -$ cd .. -# might require to run "make menuconfig" twice -$ make menuconfig -``` - -Followings are the options to set: - -* Common - * Change `Build Setup -> Build Host Platform` from _Windows_ to [_Linux_|_OSX_] - * Enable `System Type -> FPU support` - * Enable `System Type -> STM32 Peripheral Support -> SDIO` - * Enable `RTOS Features -> Clocks and Timers -> Support CLOCK_MONOTONIC` - * Enable `RTOS Features -> Pthread Options -> Enable mutex types` - * Enable `RTOS Features -> Files and I/O -> Enable /dev/console` - * Enable `RTOS Features -> Work queue support -> High priority (kernel) worker thread` - * Disable `Device Drivers -> Disable driver poll interfaces` - * Enable `Device Drivers -> MMC/SD Driver Support` - * Enable `Device Drivers -> MMC/SD Driver Support -> MMC/SD SDIO transfer support` - * Enable `Networking Support -> Networking Support` - * Enable `Networking Support -> Socket Support -> Socket options` - * Enable `Networking Support -> Unix Domain Socket Support` - * Enable `Networking Support -> TCP/IP Networking` - * Enable `Networking Support -> TCP/IP Networking -> Enable TCP/IP write buffering` - * Enable `File Systems -> FAT file system` - * Enable `File Systems -> FAT file system -> FAT upper/lower names` - * Enable `File Systems -> FAT file system -> FAT long file names` - * Enable `Device Drivers -> Network Device/PHY Support -> Late driver initialization` - * Enable `Library Routines -> Standard Math library` - * Enable `Application Configuration -> System Libraries and NSH Add-ons -> IoT.js` - * Enable all children of `Application Configuration -> System Libraries and NSH Add-ons -> readline() Support` (for those who wants to use readline) - -* For `net` module - * Enable `System Type -> STM32 Peripheral Support -> Ethernet MAC` - * Disable `System Type -> STM32 Peripheral Support -> USART2` - * Enable `System Type -> STM32 Peripheral Support -> USART6` - * Set `System Type -> Ethernet MAC configuration -> PHY address` to `0` - * Set `System Type -> Ethernet MAC configuration -> PHY Status Register Address (decimal)` to `31` - * Enable `System Type -> Ethernet MAC configuration -> PHY Status Alternate Bit Layout` - * Set `System Type -> Ethernet MAC configuration -> PHY Mode Mask` to `0x001c` - * Set `System Type -> Ethernet MAC configuration -> 10MBase-T Half Duplex Value` to `0x0004` - * Set `System Type -> Ethernet MAC configuration -> 100Base-T Half Duplex Value` to `0x0008` - * Set `System Type -> Ethernet MAC configuration -> 10Base-T Full Duplex Value` to `0x0014` - * Set `System Type -> Ethernet MAC configuration -> 10MBase-T Full Duplex Value` to `0x0018` - * Set `System Type -> Ethernet MAC configuration -> RMII clock configuration` to `External RMII clock` - * Enable `Board Selection -> STM32F4DIS-BB base board` - * Set `Device Drivers -> Network Device/PHY Support -> Board PHY Selection` to `SMSC LAN8720 PHY` - * Enable `Networking Support -> Data link support -> Local loopback` - * Enable `Networking Support -> TCP/IP Networking -> TCP/IP backlog support` - * Enable `Networking Support -> ARP Configuration -> ARP send` - -* For `dgram` - * Enable `Networking Support > UDP Networking` - -* For `pwm` module - * Enable `System Type -> STM32 Peripheral Support -> TIM(N)` - * Enable `System Type -> Timer Configuration -> TIM(N) PWM` - * Set `System Type -> Timer Configuration -> TIM(N) PWM -> TIM(n) PWM Output Channel` to channel number you want - * Enable `Device Drivers -> PWM Driver Support` - -* For `adc` module - * Enable `System Type -> STM32 Peripheral Support -> ADC(N)` - * Enable `System Type -> STM32 Peripheral Support -> TIM(M)` - * Enable `System Type -> Timer Configuration -> TIM(M) ADC` - * Enable `Device Drivers -> Analog Device(ADC/DAC) Support` - * Enable `Device Drivers -> Analog Device(ADC/DAC) Support -> Analog-to-Digital Conversion` - -* For `uart` module - * Enable `System Type -> STM32 Peripheral Support -> U[S]ART(N)` - -* For `i2c` module - * Enable `System Type -> STM32 Peripheral Support -> I2C1` - * Enable `Device Drivers -> I2C Driver Support` - -#### 4. Build IoT.js for NuttX - -##### Follow the instruction -* [Build-for-NuttX](../../../build/Build-for-NuttX.md) - -#### 5. Build NuttX - -```bash -# assuming you are in iotjs-nuttx folder -$ cd nuttx/ -$ make IOTJS_ROOT_DIR=../iotjs -``` -For release version, you can type R=1 make on the command shell. - -#### 6. Flashing - -Connect Mini-USB for power supply and connect Micro-USB for `NSH` console. - -To configure `stlink` utility for flashing, follow the instructions [here](https://github.com/texane/stlink#build-from-sources). - -To install, -```bash -# assuming you are in stlink folder -$ cd stlink -$ make -``` - -To flash, -```bash -# assuming you are in nuttx folder -$ cd nuttx -$ sudo ../stlink/build/Release/st-flash write nuttx.bin 0x8000000 -``` diff --git a/docs/targets/tizen/SystemIO-Pin-Information-Tizen.md b/docs/targets/tizen/SystemIO-Pin-Information-Tizen.md new file mode 100644 index 0000000000..55b6cb97bf --- /dev/null +++ b/docs/targets/tizen/SystemIO-Pin-Information-Tizen.md @@ -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 diff --git a/docs/targets/tizenrt/artik05x/README.md b/docs/targets/tizenrt/artik05x/README.md deleted file mode 100644 index 0951feb82a..0000000000 --- a/docs/targets/tizenrt/artik05x/README.md +++ /dev/null @@ -1,83 +0,0 @@ -### About - -This directory contains files to run IoT.js on [TizenRT](https://github.com/Samsung/TizenRT). - -WARNING: **This document is not 100% accurate since Artik05x board with tooling is not available yet** - -### How to build - -#### 1. Set up the build environment for Artik05x board - -Clone IoT.js and TizenRT into iotjs-tizenrt directory - -```bash -$ mkdir iotjs-tizenrt -$ cd iotjs-tizenrt -$ git clone https://github.com/Samsung/iotjs.git -$ git clone https://github.com/Samsung/TizenRT.git tizenrt -``` -The following directory structure is created after these commands - -```bash -iotjs-tizenrt - + iotjs - | + config - | + tizenrt - | + artik05x - + tizenrt -``` - -#### 2. Add IoT.js as a builtin application for TizenRT - -```bash -$ cd tizenrt/apps/system -$ mkdir iotjs -$ cp ../../../iotjs/config/tizenrt/artik05x/app/* ./iotjs/ -``` - -**WARNING: Manual modification is required** - -**WARNING: Below two bullet points are subject to change** - -* change tizenrt/apps/system/Kconfig to include iotjs folder - ``` - menu "IoT.js node.js like Javascript runtime" - source "$APPSDIR/system/iotjs/Kconfig" - endmenu - ``` -* Libraries required to link iotjs have to be supplied in some way - ``` - EXTRA_LIBS = -lhttpparser -liotjs -ljerrycore -ltuv -ljerry-libm - ``` - - -#### 3. Configure TizenRT - -```bash -$ cd tizenrt/os/tools -$ ./configure.sh sidk_s5jt200/hello_with_tash - -$ cd .. -# might require to run "make menuconfig" twice -$ make menuconfig -``` - -#### 4. Build IoT.js for TizenRT - -```bash -$ cd iotjs -$ ./tools/build.py --target-arch=arm --target-os=tizenrt --target-board=artik05x --sysroot=../tizenrt/os - -``` - -#### 5. Build TizenRT - -```bash -$ cd tizenrt/os -IOTJS_LIB_DIR=../iotjs/build/arm-tizenrt/debug/lib make -``` -Binaries are available in `tizenrt/build/output/bin` - -#### 6. Flashing - -Yet to be announced on [TizenRT page](https://github.com/Samsung/TizenRT#board) diff --git a/include/iotjs.h b/include/iotjs.h index a15070a863..8ec532d667 100644 --- a/include/iotjs.h +++ b/include/iotjs.h @@ -26,5 +26,7 @@ IOTJS_EXTERN_C int iotjs_entry(int argc, char** argv); +IOTJS_EXTERN_C void iotjs_conf_console_out(int (*fp)(int level, const char* fmt, + ...)); #endif /* IOTJS_IOTJS_H */ diff --git a/include/node_api.h b/include/node_api.h new file mode 100644 index 0000000000..b482ffcf87 --- /dev/null +++ b/include/node_api.h @@ -0,0 +1,704 @@ +// Pulled from nodejs/node#8742cbfef0d31d7fad49ced7d11e6827b932b101 v10.8.0 using tools/pull-napi.sh + +#ifndef SRC_NODE_API_H_ +#define SRC_NODE_API_H_ + +#include +#include +#include "node_api_types.h" + +struct uv_loop_s; // Forward declaration. + +#ifndef NAPI_VERSION +#ifdef NAPI_EXPERIMENTAL +// Use INT_MAX, this should only be consumed by the pre-processor anyway. +#define NAPI_VERSION 2147483647 +#else +// The baseline version for N-API +#define NAPI_VERSION 3 +#endif +#endif + +#ifdef _WIN32 + #ifdef BUILDING_NODE_EXTENSION + #ifdef EXTERNAL_NAPI + // Building external N-API, or native module against external N-API + #define NAPI_EXTERN /* nothing */ + #else + // Building native module against node with built-in N-API + #define NAPI_EXTERN __declspec(dllimport) + #endif + #else + // Building node with built-in N-API + #define NAPI_EXTERN __declspec(dllexport) + #endif +#else + #define NAPI_EXTERN /* nothing */ +#endif + +#ifdef _WIN32 +# define NAPI_MODULE_EXPORT __declspec(dllexport) +#else +# define NAPI_MODULE_EXPORT __attribute__((visibility("default"))) +#endif + +#ifdef __GNUC__ +#define NAPI_NO_RETURN __attribute__((noreturn)) +#else +#define NAPI_NO_RETURN +#endif + + +typedef napi_value (*napi_addon_register_func)(napi_env env, + napi_value exports); + +typedef struct { + int nm_version; + unsigned int nm_flags; + const char* nm_filename; + napi_addon_register_func nm_register_func; + const char* nm_modname; + void* nm_priv; + void* reserved[4]; +} napi_module; + +#define NAPI_MODULE_VERSION 1 + +#if defined(_MSC_VER) +#pragma section(".CRT$XCU", read) +#define NAPI_C_CTOR(fn) \ + static void __cdecl fn(void); \ + __declspec(dllexport, allocate(".CRT$XCU")) void(__cdecl * fn##_)(void) = \ + fn; \ + static void __cdecl fn(void) +#else +#define NAPI_C_CTOR(fn) \ + static void fn(void) __attribute__((constructor)); \ + static void fn(void) +#endif + +#ifdef __cplusplus +#define EXTERN_C_START extern "C" { +#define EXTERN_C_END } +#else +#define EXTERN_C_START +#define EXTERN_C_END +#endif + +#define NAPI_MODULE_X(modname, regfunc, priv, flags) \ + EXTERN_C_START \ + static napi_module _module = \ + { \ + NAPI_MODULE_VERSION, \ + flags, \ + __FILE__, \ + regfunc, \ + #modname, \ + priv, \ + {0}, \ + }; \ + NAPI_C_CTOR(_register_ ## modname) { \ + napi_module_register(&_module); \ + } \ + EXTERN_C_END + +#define NAPI_MODULE(modname, regfunc) \ + NAPI_MODULE_X(modname, regfunc, NULL, 0) // NOLINT (readability/null_usage) + +#define NAPI_MODULE_INITIALIZER_BASE napi_register_module_v + +#define NAPI_MODULE_INITIALIZER_X(base, version) \ + NAPI_MODULE_INITIALIZER_X_HELPER(base, version) +#define NAPI_MODULE_INITIALIZER_X_HELPER(base, version) base##version + +#define NAPI_MODULE_INITIALIZER \ + NAPI_MODULE_INITIALIZER_X(NAPI_MODULE_INITIALIZER_BASE, \ + NAPI_MODULE_VERSION) + +#define NAPI_MODULE_INIT() \ + EXTERN_C_START \ + NAPI_MODULE_EXPORT napi_value \ + NAPI_MODULE_INITIALIZER(napi_env env, napi_value exports); \ + EXTERN_C_END \ + NAPI_MODULE(NODE_GYP_MODULE_NAME, NAPI_MODULE_INITIALIZER) \ + napi_value NAPI_MODULE_INITIALIZER(napi_env env, \ + napi_value exports) + +#define NAPI_AUTO_LENGTH SIZE_MAX + +EXTERN_C_START + +NAPI_EXTERN void napi_module_register(napi_module* mod); + +NAPI_EXTERN napi_status +napi_get_last_error_info(napi_env env, + const napi_extended_error_info** result); + +NAPI_EXTERN NAPI_NO_RETURN void napi_fatal_error(const char* location, + size_t location_len, + const char* message, + size_t message_len); + +// Getters for defined singletons +NAPI_EXTERN napi_status napi_get_undefined(napi_env env, napi_value* result); +NAPI_EXTERN napi_status napi_get_null(napi_env env, napi_value* result); +NAPI_EXTERN napi_status napi_get_global(napi_env env, napi_value* result); +NAPI_EXTERN napi_status napi_get_boolean(napi_env env, + bool value, + napi_value* result); + +// Methods to create Primitive types/Objects +NAPI_EXTERN napi_status napi_create_object(napi_env env, napi_value* result); +NAPI_EXTERN napi_status napi_create_array(napi_env env, napi_value* result); +NAPI_EXTERN napi_status napi_create_array_with_length(napi_env env, + size_t length, + napi_value* result); +NAPI_EXTERN napi_status napi_create_double(napi_env env, + double value, + napi_value* result); +NAPI_EXTERN napi_status napi_create_int32(napi_env env, + int32_t value, + napi_value* result); +NAPI_EXTERN napi_status napi_create_uint32(napi_env env, + uint32_t value, + napi_value* result); +NAPI_EXTERN napi_status napi_create_int64(napi_env env, + int64_t value, + napi_value* result); +NAPI_EXTERN napi_status napi_create_string_latin1(napi_env env, + const char* str, + size_t length, + napi_value* result); +NAPI_EXTERN napi_status napi_create_string_utf8(napi_env env, + const char* str, + size_t length, + napi_value* result); +NAPI_EXTERN napi_status napi_create_string_utf16(napi_env env, + const char16_t* str, + size_t length, + napi_value* result); +NAPI_EXTERN napi_status napi_create_symbol(napi_env env, + napi_value description, + napi_value* result); +NAPI_EXTERN napi_status napi_create_function(napi_env env, + const char* utf8name, + size_t length, + napi_callback cb, + void* data, + napi_value* result); +NAPI_EXTERN napi_status napi_create_error(napi_env env, + napi_value code, + napi_value msg, + napi_value* result); +NAPI_EXTERN napi_status napi_create_type_error(napi_env env, + napi_value code, + napi_value msg, + napi_value* result); +NAPI_EXTERN napi_status napi_create_range_error(napi_env env, + napi_value code, + napi_value msg, + napi_value* result); + +// Methods to get the native napi_value from Primitive type +NAPI_EXTERN napi_status napi_typeof(napi_env env, + napi_value value, + napi_valuetype* result); +NAPI_EXTERN napi_status napi_get_value_double(napi_env env, + napi_value value, + double* result); +NAPI_EXTERN napi_status napi_get_value_int32(napi_env env, + napi_value value, + int32_t* result); +NAPI_EXTERN napi_status napi_get_value_uint32(napi_env env, + napi_value value, + uint32_t* result); +NAPI_EXTERN napi_status napi_get_value_int64(napi_env env, + napi_value value, + int64_t* result); +NAPI_EXTERN napi_status napi_get_value_bool(napi_env env, + napi_value value, + bool* result); + +// Copies LATIN-1 encoded bytes from a string into a buffer. +NAPI_EXTERN napi_status napi_get_value_string_latin1(napi_env env, + napi_value value, + char* buf, + size_t bufsize, + size_t* result); + +// Copies UTF-8 encoded bytes from a string into a buffer. +NAPI_EXTERN napi_status napi_get_value_string_utf8(napi_env env, + napi_value value, + char* buf, + size_t bufsize, + size_t* result); + +// Copies UTF-16 encoded bytes from a string into a buffer. +NAPI_EXTERN napi_status napi_get_value_string_utf16(napi_env env, + napi_value value, + char16_t* buf, + size_t bufsize, + size_t* result); + +// Methods to coerce values +// These APIs may execute user scripts +NAPI_EXTERN napi_status napi_coerce_to_bool(napi_env env, + napi_value value, + napi_value* result); +NAPI_EXTERN napi_status napi_coerce_to_number(napi_env env, + napi_value value, + napi_value* result); +NAPI_EXTERN napi_status napi_coerce_to_object(napi_env env, + napi_value value, + napi_value* result); +NAPI_EXTERN napi_status napi_coerce_to_string(napi_env env, + napi_value value, + napi_value* result); + +// Methods to work with Objects +NAPI_EXTERN napi_status napi_get_prototype(napi_env env, + napi_value object, + napi_value* result); +NAPI_EXTERN napi_status napi_get_property_names(napi_env env, + napi_value object, + napi_value* result); +NAPI_EXTERN napi_status napi_set_property(napi_env env, + napi_value object, + napi_value key, + napi_value value); +NAPI_EXTERN napi_status napi_has_property(napi_env env, + napi_value object, + napi_value key, + bool* result); +NAPI_EXTERN napi_status napi_get_property(napi_env env, + napi_value object, + napi_value key, + napi_value* result); +NAPI_EXTERN napi_status napi_delete_property(napi_env env, + napi_value object, + napi_value key, + bool* result); +NAPI_EXTERN napi_status napi_has_own_property(napi_env env, + napi_value object, + napi_value key, + bool* result); +NAPI_EXTERN napi_status napi_set_named_property(napi_env env, + napi_value object, + const char* utf8name, + napi_value value); +NAPI_EXTERN napi_status napi_has_named_property(napi_env env, + napi_value object, + const char* utf8name, + bool* result); +NAPI_EXTERN napi_status napi_get_named_property(napi_env env, + napi_value object, + const char* utf8name, + napi_value* result); +NAPI_EXTERN napi_status napi_set_element(napi_env env, + napi_value object, + uint32_t index, + napi_value value); +NAPI_EXTERN napi_status napi_has_element(napi_env env, + napi_value object, + uint32_t index, + bool* result); +NAPI_EXTERN napi_status napi_get_element(napi_env env, + napi_value object, + uint32_t index, + napi_value* result); +NAPI_EXTERN napi_status napi_delete_element(napi_env env, + napi_value object, + uint32_t index, + bool* result); +NAPI_EXTERN napi_status +napi_define_properties(napi_env env, + napi_value object, + size_t property_count, + const napi_property_descriptor* properties); + +// Methods to work with Arrays +NAPI_EXTERN napi_status napi_is_array(napi_env env, + napi_value value, + bool* result); +NAPI_EXTERN napi_status napi_get_array_length(napi_env env, + napi_value value, + uint32_t* result); + +// Methods to compare values +NAPI_EXTERN napi_status napi_strict_equals(napi_env env, + napi_value lhs, + napi_value rhs, + bool* result); + +// Methods to work with Functions +NAPI_EXTERN napi_status napi_call_function(napi_env env, + napi_value recv, + napi_value func, + size_t argc, + const napi_value* argv, + napi_value* result); +NAPI_EXTERN napi_status napi_new_instance(napi_env env, + napi_value constructor, + size_t argc, + const napi_value* argv, + napi_value* result); +NAPI_EXTERN napi_status napi_instanceof(napi_env env, + napi_value object, + napi_value constructor, + bool* result); + +// Methods to work with napi_callbacks + +// Gets all callback info in a single call. (Ugly, but faster.) +NAPI_EXTERN napi_status napi_get_cb_info( + napi_env env, // [in] NAPI environment handle + napi_callback_info cbinfo, // [in] Opaque callback-info handle + size_t* argc, // [in-out] Specifies the size of the provided argv array + // and receives the actual count of args. + napi_value* argv, // [out] Array of values + napi_value* this_arg, // [out] Receives the JS 'this' arg for the call + void** data); // [out] Receives the data pointer for the callback. + +NAPI_EXTERN napi_status napi_get_new_target(napi_env env, + napi_callback_info cbinfo, + napi_value* result); +NAPI_EXTERN napi_status +napi_define_class(napi_env env, + const char* utf8name, + size_t length, + napi_callback constructor, + void* data, + size_t property_count, + const napi_property_descriptor* properties, + napi_value* result); + +// Methods to work with external data objects +NAPI_EXTERN napi_status napi_wrap(napi_env env, + napi_value js_object, + void* native_object, + napi_finalize finalize_cb, + void* finalize_hint, + napi_ref* result); +NAPI_EXTERN napi_status napi_unwrap(napi_env env, + napi_value js_object, + void** result); +NAPI_EXTERN napi_status napi_remove_wrap(napi_env env, + napi_value js_object, + void** result); +NAPI_EXTERN napi_status napi_create_external(napi_env env, + void* data, + napi_finalize finalize_cb, + void* finalize_hint, + napi_value* result); +NAPI_EXTERN napi_status napi_get_value_external(napi_env env, + napi_value value, + void** result); + +// Methods to control object lifespan + +// Set initial_refcount to 0 for a weak reference, >0 for a strong reference. +NAPI_EXTERN napi_status napi_create_reference(napi_env env, + napi_value value, + uint32_t initial_refcount, + napi_ref* result); + +// Deletes a reference. The referenced value is released, and may +// be GC'd unless there are other references to it. +NAPI_EXTERN napi_status napi_delete_reference(napi_env env, napi_ref ref); + +// Increments the reference count, optionally returning the resulting count. +// After this call the reference will be a strong reference because its +// refcount is >0, and the referenced object is effectively "pinned". +// Calling this when the refcount is 0 and the object is unavailable +// results in an error. +NAPI_EXTERN napi_status napi_reference_ref(napi_env env, + napi_ref ref, + uint32_t* result); + +// Decrements the reference count, optionally returning the resulting count. +// If the result is 0 the reference is now weak and the object may be GC'd +// at any time if there are no other references. Calling this when the +// refcount is already 0 results in an error. +NAPI_EXTERN napi_status napi_reference_unref(napi_env env, + napi_ref ref, + uint32_t* result); + +// Attempts to get a referenced value. If the reference is weak, +// the value might no longer be available, in that case the call +// is still successful but the result is NULL. +NAPI_EXTERN napi_status napi_get_reference_value(napi_env env, + napi_ref ref, + napi_value* result); + +NAPI_EXTERN napi_status napi_open_handle_scope(napi_env env, + napi_handle_scope* result); +NAPI_EXTERN napi_status napi_close_handle_scope(napi_env env, + napi_handle_scope scope); +NAPI_EXTERN napi_status +napi_open_escapable_handle_scope(napi_env env, + napi_escapable_handle_scope* result); +NAPI_EXTERN napi_status +napi_close_escapable_handle_scope(napi_env env, + napi_escapable_handle_scope scope); + +NAPI_EXTERN napi_status napi_escape_handle(napi_env env, + napi_escapable_handle_scope scope, + napi_value escapee, + napi_value* result); + +// Methods to support error handling +NAPI_EXTERN napi_status napi_throw(napi_env env, napi_value error); +NAPI_EXTERN napi_status napi_throw_error(napi_env env, + const char* code, + const char* msg); +NAPI_EXTERN napi_status napi_throw_type_error(napi_env env, + const char* code, + const char* msg); +NAPI_EXTERN napi_status napi_throw_range_error(napi_env env, + const char* code, + const char* msg); +NAPI_EXTERN napi_status napi_is_error(napi_env env, + napi_value value, + bool* result); + +// Methods to support catching exceptions +NAPI_EXTERN napi_status napi_is_exception_pending(napi_env env, bool* result); +NAPI_EXTERN napi_status napi_get_and_clear_last_exception(napi_env env, + napi_value* result); + +// Methods to provide node::Buffer functionality with napi types +NAPI_EXTERN napi_status napi_create_buffer(napi_env env, + size_t length, + void** data, + napi_value* result); +NAPI_EXTERN napi_status napi_create_external_buffer(napi_env env, + size_t length, + void* data, + napi_finalize finalize_cb, + void* finalize_hint, + napi_value* result); +NAPI_EXTERN napi_status napi_create_buffer_copy(napi_env env, + size_t length, + const void* data, + void** result_data, + napi_value* result); +NAPI_EXTERN napi_status napi_is_buffer(napi_env env, + napi_value value, + bool* result); +NAPI_EXTERN napi_status napi_get_buffer_info(napi_env env, + napi_value value, + void** data, + size_t* length); + +// Methods to work with array buffers and typed arrays +NAPI_EXTERN napi_status napi_is_arraybuffer(napi_env env, + napi_value value, + bool* result); +NAPI_EXTERN napi_status napi_create_arraybuffer(napi_env env, + size_t byte_length, + void** data, + napi_value* result); +NAPI_EXTERN napi_status +napi_create_external_arraybuffer(napi_env env, + void* external_data, + size_t byte_length, + napi_finalize finalize_cb, + void* finalize_hint, + napi_value* result); +NAPI_EXTERN napi_status napi_get_arraybuffer_info(napi_env env, + napi_value arraybuffer, + void** data, + size_t* byte_length); +NAPI_EXTERN napi_status napi_is_typedarray(napi_env env, + napi_value value, + bool* result); +NAPI_EXTERN napi_status napi_create_typedarray(napi_env env, + napi_typedarray_type type, + size_t length, + napi_value arraybuffer, + size_t byte_offset, + napi_value* result); +NAPI_EXTERN napi_status napi_get_typedarray_info(napi_env env, + napi_value typedarray, + napi_typedarray_type* type, + size_t* length, + void** data, + napi_value* arraybuffer, + size_t* byte_offset); + +NAPI_EXTERN napi_status napi_create_dataview(napi_env env, + size_t length, + napi_value arraybuffer, + size_t byte_offset, + napi_value* result); +NAPI_EXTERN napi_status napi_is_dataview(napi_env env, + napi_value value, + bool* result); +NAPI_EXTERN napi_status napi_get_dataview_info(napi_env env, + napi_value dataview, + size_t* bytelength, + void** data, + napi_value* arraybuffer, + size_t* byte_offset); + +// Methods to manage simple async operations +NAPI_EXTERN +napi_status napi_create_async_work(napi_env env, + napi_value async_resource, + napi_value async_resource_name, + napi_async_execute_callback execute, + napi_async_complete_callback complete, + void* data, + napi_async_work* result); +NAPI_EXTERN napi_status napi_delete_async_work(napi_env env, + napi_async_work work); +NAPI_EXTERN napi_status napi_queue_async_work(napi_env env, + napi_async_work work); +NAPI_EXTERN napi_status napi_cancel_async_work(napi_env env, + napi_async_work work); + +// Methods for custom handling of async operations +NAPI_EXTERN napi_status napi_async_init(napi_env env, + napi_value async_resource, + napi_value async_resource_name, + napi_async_context* result); + +NAPI_EXTERN napi_status napi_async_destroy(napi_env env, + napi_async_context async_context); + +NAPI_EXTERN napi_status napi_make_callback(napi_env env, + napi_async_context async_context, + napi_value recv, + napi_value func, + size_t argc, + const napi_value* argv, + napi_value* result); + +// version management +NAPI_EXTERN napi_status napi_get_version(napi_env env, uint32_t* result); + +NAPI_EXTERN +napi_status napi_get_node_version(napi_env env, + const napi_node_version** version); + +// Promises +NAPI_EXTERN napi_status napi_create_promise(napi_env env, + napi_deferred* deferred, + napi_value* promise); +NAPI_EXTERN napi_status napi_resolve_deferred(napi_env env, + napi_deferred deferred, + napi_value resolution); +NAPI_EXTERN napi_status napi_reject_deferred(napi_env env, + napi_deferred deferred, + napi_value rejection); +NAPI_EXTERN napi_status napi_is_promise(napi_env env, + napi_value promise, + bool* is_promise); + +// Memory management +NAPI_EXTERN napi_status napi_adjust_external_memory(napi_env env, + int64_t change_in_bytes, + int64_t* adjusted_value); + +// Runnig a script +NAPI_EXTERN napi_status napi_run_script(napi_env env, + napi_value script, + napi_value* result); + +#if NAPI_VERSION >= 2 + +// Return the current libuv event loop for a given environment +NAPI_EXTERN napi_status napi_get_uv_event_loop(napi_env env, + struct uv_loop_s** loop); + +#endif // NAPI_VERSION >= 2 + +#if NAPI_VERSION >= 3 + +NAPI_EXTERN napi_status napi_open_callback_scope(napi_env env, + napi_value resource_object, + napi_async_context context, + napi_callback_scope* result); + +NAPI_EXTERN napi_status napi_close_callback_scope(napi_env env, + napi_callback_scope scope); + +NAPI_EXTERN napi_status napi_fatal_exception(napi_env env, napi_value err); + +NAPI_EXTERN napi_status napi_add_env_cleanup_hook(napi_env env, + void (*fun)(void* arg), + void* arg); + +NAPI_EXTERN napi_status napi_remove_env_cleanup_hook(napi_env env, + void (*fun)(void* arg), + void* arg); + +#endif // NAPI_VERSION >= 3 + +#ifdef NAPI_EXPERIMENTAL + +// Calling into JS from other threads +NAPI_EXTERN napi_status +napi_create_threadsafe_function(napi_env env, + napi_value func, + napi_value async_resource, + napi_value async_resource_name, + size_t max_queue_size, + size_t initial_thread_count, + void* thread_finalize_data, + napi_finalize thread_finalize_cb, + void* context, + napi_threadsafe_function_call_js call_js_cb, + napi_threadsafe_function* result); + +NAPI_EXTERN napi_status +napi_get_threadsafe_function_context(napi_threadsafe_function func, + void** result); + +NAPI_EXTERN napi_status +napi_call_threadsafe_function(napi_threadsafe_function func, + void* data, + napi_threadsafe_function_call_mode is_blocking); + +NAPI_EXTERN napi_status +napi_acquire_threadsafe_function(napi_threadsafe_function func); + +NAPI_EXTERN napi_status +napi_release_threadsafe_function(napi_threadsafe_function func, + napi_threadsafe_function_release_mode mode); + +NAPI_EXTERN napi_status +napi_unref_threadsafe_function(napi_env env, napi_threadsafe_function func); + +NAPI_EXTERN napi_status +napi_ref_threadsafe_function(napi_env env, napi_threadsafe_function func); + +NAPI_EXTERN napi_status napi_create_bigint_int64(napi_env env, + int64_t value, + napi_value* result); +NAPI_EXTERN napi_status napi_create_bigint_uint64(napi_env env, + uint64_t value, + napi_value* result); +NAPI_EXTERN napi_status napi_create_bigint_words(napi_env env, + int sign_bit, + size_t word_count, + const uint64_t* words, + napi_value* result); +NAPI_EXTERN napi_status napi_get_value_bigint_int64(napi_env env, + napi_value value, + int64_t* result, + bool* lossless); +NAPI_EXTERN napi_status napi_get_value_bigint_uint64(napi_env env, + napi_value value, + uint64_t* result, + bool* lossless); +NAPI_EXTERN napi_status napi_get_value_bigint_words(napi_env env, + napi_value value, + int* sign_bit, + size_t* word_count, + uint64_t* words); +#endif // NAPI_EXPERIMENTAL + +EXTERN_C_END + +#endif // SRC_NODE_API_H_ diff --git a/include/node_api_types.h b/include/node_api_types.h new file mode 100644 index 0000000000..5755a7d65a --- /dev/null +++ b/include/node_api_types.h @@ -0,0 +1,147 @@ +// Pulled from nodejs/node#8742cbfef0d31d7fad49ced7d11e6827b932b101 v10.8.0 using tools/pull-napi.sh + +#ifndef SRC_NODE_API_TYPES_H_ +#define SRC_NODE_API_TYPES_H_ + +#include +#include + +#if !defined __cplusplus || (defined(_MSC_VER) && _MSC_VER < 1900) + typedef uint16_t char16_t; +#endif + +// JSVM API types are all opaque pointers for ABI stability +// typedef undefined structs instead of void* for compile time type safety +typedef struct napi_env__* napi_env; +typedef struct napi_value__* napi_value; +typedef struct napi_ref__* napi_ref; +typedef struct napi_handle_scope__* napi_handle_scope; +typedef struct napi_escapable_handle_scope__* napi_escapable_handle_scope; +typedef struct napi_callback_scope__* napi_callback_scope; +typedef struct napi_callback_info__* napi_callback_info; +typedef struct napi_async_context__* napi_async_context; +typedef struct napi_async_work__* napi_async_work; +typedef struct napi_deferred__* napi_deferred; +#ifdef NAPI_EXPERIMENTAL +typedef struct napi_threadsafe_function__* napi_threadsafe_function; +#endif // NAPI_EXPERIMENTAL + +typedef enum { + napi_default = 0, + napi_writable = 1 << 0, + napi_enumerable = 1 << 1, + napi_configurable = 1 << 2, + + // Used with napi_define_class to distinguish static properties + // from instance properties. Ignored by napi_define_properties. + napi_static = 1 << 10, +} napi_property_attributes; + +typedef enum { + // ES6 types (corresponds to typeof) + napi_undefined, + napi_null, + napi_boolean, + napi_number, + napi_string, + napi_symbol, + napi_object, + napi_function, + napi_external, + napi_bigint, +} napi_valuetype; + +typedef enum { + napi_int8_array, + napi_uint8_array, + napi_uint8_clamped_array, + napi_int16_array, + napi_uint16_array, + napi_int32_array, + napi_uint32_array, + napi_float32_array, + napi_float64_array, + napi_bigint64_array, + napi_biguint64_array, +} napi_typedarray_type; + +typedef enum { + napi_ok, + napi_invalid_arg, + napi_object_expected, + napi_string_expected, + napi_name_expected, + napi_function_expected, + napi_number_expected, + napi_boolean_expected, + napi_array_expected, + napi_generic_failure, + napi_pending_exception, + napi_cancelled, + napi_escape_called_twice, + napi_handle_scope_mismatch, + napi_callback_scope_mismatch, + napi_queue_full, + napi_closing, + napi_bigint_expected, +} napi_status; + +#ifdef NAPI_EXPERIMENTAL +typedef enum { + napi_tsfn_release, + napi_tsfn_abort +} napi_threadsafe_function_release_mode; + +typedef enum { + napi_tsfn_nonblocking, + napi_tsfn_blocking +} napi_threadsafe_function_call_mode; +#endif // NAPI_EXPERIMENTAL + +typedef napi_value (*napi_callback)(napi_env env, + napi_callback_info info); +typedef void (*napi_finalize)(napi_env env, + void* finalize_data, + void* finalize_hint); +typedef void (*napi_async_execute_callback)(napi_env env, + void* data); +typedef void (*napi_async_complete_callback)(napi_env env, + napi_status status, + void* data); + +#ifdef NAPI_EXPERIMENTAL +typedef void (*napi_threadsafe_function_call_js)(napi_env env, + napi_value js_callback, + void* context, + void* data); +#endif // NAPI_EXPERIMENTAL + +typedef struct { + // One of utf8name or name should be NULL. + const char* utf8name; + napi_value name; + + napi_callback method; + napi_callback getter; + napi_callback setter; + napi_value value; + + napi_property_attributes attributes; + void* data; +} napi_property_descriptor; + +typedef struct { + const char* error_message; + void* engine_reserved; + uint32_t engine_error_code; + napi_status error_code; +} napi_extended_error_info; + +typedef struct { + uint32_t major; + uint32_t minor; + uint32_t patch; + const char* release; +} napi_node_version; + +#endif // SRC_NODE_API_TYPES_H_ diff --git a/package.json b/package.json new file mode 100644 index 0000000000..52a7c4552d --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "name": "IoT.js", + "description": "Platform for Internet of Things with JavaScript", + "scripts": { + "lint": "eslint src -f codeframe || true", + "lint-autofix": "eslint src -f codeframe --fix || true" + }, + "author": "Samsung Electronics Co., Ltd.", + "license": "Apache-2.0", + "devDependencies": { + "eslint": "^4.7.2" + }, + "dependencies": { + "node-gyp": "^3.8.0" + } +} diff --git a/profiles/default.profile b/profiles/default.profile new file mode 100644 index 0000000000..d496e8f8bf --- /dev/null +++ b/profiles/default.profile @@ -0,0 +1,2 @@ +ENABLE_MODULE_IOTJS_BASIC_MODULES +ENABLE_MODULE_IOTJS_CORE_MODULES diff --git a/profiles/minimal.profile b/profiles/minimal.profile new file mode 100644 index 0000000000..d425af7477 --- /dev/null +++ b/profiles/minimal.profile @@ -0,0 +1 @@ +ENABLE_MODULE_IOTJS_CORE_MODULES diff --git a/samples/http_hello/client_post.js b/samples/http_hello/client_post.js deleted file mode 100644 index 277bb0d26f..0000000000 --- a/samples/http_hello/client_post.js +++ /dev/null @@ -1,50 +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 http = require('http'); - -var message = JSON.stringify({ - greeting: 'Hello, IoT.JS!', - answer: '', -}); - -var options = { - hostname: '127.0.0.1', - port: 8080, - path: '/', - method: 'POST', - headers: { - 'Content-Length': message.length - } -}; - -http.request(options, function (res) { - receive(res, function (data) { - var obj = JSON.parse(data); - console.log(obj.answer); - }); -}).end(message); - -function receive(incoming, callback) { - var data = ''; - - incoming.on('data', function (chunk) { - data += chunk; - }); - - incoming.on('end', function () { - callback ? callback(data) : ''; - }); -} diff --git a/samples/http_hello/server.js b/samples/http_hello/server.js deleted file mode 100644 index 3fcbe48a9f..0000000000 --- a/samples/http_hello/server.js +++ /dev/null @@ -1,60 +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 http = require('http'); -var port = 8080; - -http.createServer(function (req, res) { - if (req.method == 'GET') { - status(res, 'Hello, IoT.JS!'); - - } else if (req.method == 'POST') { - receive(req, function (data) { - var obj = JSON.parse(data); - obj.answer = 'Hello, There!' - status(res, obj); - }); - } -}).listen(port); - -function receive(incoming, callback) { - var data = ''; - - incoming.on('data', function (chunk) { - data += chunk; - }); - - incoming.on('end', function () { - callback ? callback(data) : ''; - }); -} - -function status(res, data) { - var isJson = (typeof data === 'object'); - - if (isJson) { - data = JSON.stringify(data); - } - - var headers = { - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Headers': - 'Origin, X-Requested-With, Content-Type, Accept', - 'Content-Type': isJson ? 'application/json' : 'text/plain', - }; - - res.writeHead(200, headers); - res.end(data); -}; diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 0000000000..fe91756d56 --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,4 @@ +sonar.projectKey=pando-project_iotjs +sonar.projectName=IoT.js +sonar.sources=src +sonar.cfamily.build-wrapper-output=bw-output diff --git a/src/internal/node_api_internal.h b/src/internal/node_api_internal.h new file mode 100644 index 0000000000..c1f67a6572 --- /dev/null +++ b/src/internal/node_api_internal.h @@ -0,0 +1,161 @@ +/* Copyright 2019-present Samsung Electronics Co., Ltd. and other contributors + * Copyright 2018-present Rokid 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_NODE_API_H +#define IOTJS_NODE_API_H + +#include "iotjs_def.h" +#include "jerryscript-ext/handle-scope.h" +#include "jerryscript.h" +#include "internal/node_api_internal_types.h" +#include "node_api.h" + +#define GET_4TH_ARG(arg1, arg2, arg3, arg4, ...) arg4 + +#define AS_JERRY_VALUE(nvalue) (jerry_value_t)(uintptr_t) nvalue +#define AS_NAPI_VALUE(jval) (napi_value)(uintptr_t) jval + +/** + * MARK: - N-API Returns machenism: + * If any non-napi-ok status code is returned in N-API functions, there + * should be an error code and error message temporarily stored in napi-env + * and can be fetched by `napi_get_last_error_info` until next napi function + * called. + */ +#define NAPI_RETURN_WITH_MSG(status, message) \ + do { \ + iotjs_napi_set_error_info(iotjs_get_current_napi_env(), status, message, \ + 0, NULL); \ + return status; \ + } while (0) + +#define NAPI_RETURN(status) \ + do { \ + iotjs_napi_set_error_info(iotjs_get_current_napi_env(), status, NULL, 0, \ + NULL); \ + return status; \ + } while (0) +/** MARK: - END N-API Returns */ + +/** MARK: - N-API Asserts */ +/** + * A weak assertion, which don't crash the program on failed assertion + * rather returning a napi error code back to caller. + */ +#define NAPI_WEAK_ASSERT(error_t, assertion) \ + do { \ + if (!(assertion)) \ + NAPI_RETURN_WITH_MSG(error_t, "Assertion (" #assertion ") failed"); \ + } while (0) + +#define NAPI_WEAK_ASSERT_WITH_MSG(error_t, assertion, message) \ + do { \ + if (!(assertion)) \ + NAPI_RETURN_WITH_MSG(error_t, message); \ + } while (0) + +/** + * A convenience weak assertion on jerry value type. + */ +#define NAPI_TRY_TYPE(type, jval) \ + NAPI_WEAK_ASSERT_WITH_MSG(napi_##type##_expected, \ + jerry_value_is_##type(jval), \ + #type " was expected") + +/** + * A convenience weak assertion on N-API Env matching. + */ +#define NAPI_TRY_ENV(env) \ + do { \ + if (napi_try_env_helper(env)) { \ + NAPI_RETURN_WITH_MSG(napi_invalid_arg, "N-API env not match."); \ + } \ + } while (0) + +/** + * A convenience weak assertion expecting there is no pending exception + * unhandled. + */ +#define NAPI_TRY_NO_PENDING_EXCEPTION(env) \ + NAPI_WEAK_ASSERT(napi_pending_exception, \ + !iotjs_napi_is_exception_pending(env)) +/** MARK: - N-API Asserts */ + +/** + * In most N-API functions, there is an in-out pointer parameter to retrieve + * return values, yet this pointer could be NULL anyway - it has to be ensured + * no value were unexpectedly written to NULL pointer. + */ +#define NAPI_ASSIGN(result, value) \ + if ((result) != NULL) \ + *(result) = (value); + +/** + * A convenience macro to call N-API functions internally and handle it's + * non-napi-ok status code. + */ +#define NAPI_INTERNAL_CALL(call) \ + do { \ + napi_status status = (call); \ + if (status != napi_ok) { \ + NAPI_RETURN(status); \ + } \ + } while (0) + +/** + * A convenience macro to create jerry-values and add it to current top + * handle scope. + */ +#define JERRYX_CREATE(var, create) \ + jerry_value_t var = (create); \ + jerryx_create_handle(var); + +/** MARK: - node_api_module.c */ +int napi_module_init_pending(jerry_value_t* exports); +/** MARK: - END node_api_module.c */ + +/** MARK: - node_api_env.c */ +napi_env iotjs_get_current_napi_env(void); +bool napi_try_env_helper(napi_env env); +void iotjs_napi_set_current_callback(napi_env env, + iotjs_callback_info_t* callback_info); +iotjs_callback_info_t* iotjs_napi_get_current_callback(napi_env env); + +void iotjs_napi_set_error_info(napi_env env, napi_status error_code, + const char* error_message, + uint32_t engine_error_code, + void* engine_reserved); +void iotjs_napi_clear_error_info(napi_env env); + +bool iotjs_napi_is_exception_pending(napi_env env); +jerry_value_t iotjs_napi_env_get_and_clear_exception(napi_env env); +jerry_value_t iotjs_napi_env_get_and_clear_fatal_exception(napi_env env); +/** MARK: - END node_api_env.c */ + +/** MARK: - node_api_lifetime.c */ +napi_status jerryx_status_to_napi_status(jerryx_handle_scope_status status); +iotjs_object_info_t* iotjs_get_object_native_info(jerry_value_t jval, + size_t native_info_size); +iotjs_object_info_t* iotjs_try_get_object_native_info(jerry_value_t jval, + size_t native_info_size); +void iotjs_setup_napi(void); +void iotjs_cleanup_napi(void); +/** MARK: - END node_api_lifetime.c */ + +napi_status napi_assign_bool(bool value, bool* result); +napi_status napi_assign_nvalue(jerry_value_t jvalue, napi_value* nvalue); + +#endif // IOTJS_NODE_API_H diff --git a/src/internal/node_api_internal_types.h b/src/internal/node_api_internal_types.h new file mode 100644 index 0000000000..0f2b813d3d --- /dev/null +++ b/src/internal/node_api_internal_types.h @@ -0,0 +1,122 @@ + +/* Copyright 2018-present Rokid 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_NODE_API_TYPES_H +#define IOTJS_NODE_API_TYPES_H + +#include "jerryscript.h" +#include +#include "node_api.h" + +typedef void (*iotjs_cleanup_hook_fn)(void* arg); + +typedef struct iotjs_async_context_s iotjs_async_context_t; +typedef struct iotjs_async_work_s iotjs_async_work_t; +typedef struct iotjs_buffer_external_info_s iotjs_buffer_external_info_t; +typedef struct iotjs_callback_info_s iotjs_callback_info_t; +typedef struct iotjs_cleanup_hook_s iotjs_cleanup_hook_t; +typedef struct iotjs_function_info_s iotjs_function_info_t; +typedef struct iotjs_napi_env_s iotjs_napi_env_t; +typedef struct iotjs_object_info_s iotjs_object_info_t; +typedef struct iotjs_reference_s iotjs_reference_t; + +typedef enum { + napi_module_load_ok = 0, + + napi_module_no_pending, + napi_module_no_nm_register_func, +} napi_module_load_status; + +struct iotjs_cleanup_hook_s { + iotjs_cleanup_hook_fn fn; + void* arg; + iotjs_cleanup_hook_t* next; +}; + +struct iotjs_buffer_external_info_s { + napi_env env; + void* external_data; + void* finalize_hint; + napi_finalize finalize_cb; +}; + +struct iotjs_reference_s { + jerry_value_t jval; + uint32_t refcount; + + iotjs_reference_t* prev; + iotjs_reference_t* next; +}; + +#define IOTJS_OBJECT_INFO_FIELDS \ + napi_env env; \ + void* native_object; \ + napi_finalize finalize_cb; \ + void* finalize_hint; \ + iotjs_reference_t* ref_start; \ + iotjs_reference_t* ref_end; + +struct iotjs_object_info_s { + IOTJS_OBJECT_INFO_FIELDS +}; + +struct iotjs_function_info_s { + IOTJS_OBJECT_INFO_FIELDS + + napi_callback cb; + void* data; +}; + +struct iotjs_callback_info_s { + size_t argc; + jerry_value_t* argv; + jerry_value_t jval_this; + jerry_value_t jval_func; + + jerryx_handle_scope handle_scope; + iotjs_function_info_t* function_info; +}; + +struct iotjs_napi_env_s { + napi_value pending_exception; + napi_value pending_fatal_exception; + napi_extended_error_info extended_error_info; + + /** Common function context */ + iotjs_callback_info_t* current_callback_info; + uv_thread_t main_thread; + + iotjs_cleanup_hook_t* cleanup_hook; +}; + +struct iotjs_async_work_s { + uv_work_t work_req; + + napi_env env; + napi_value async_resource; + napi_value async_resource_name; + napi_async_execute_callback execute; + napi_async_complete_callback complete; + void* data; +}; + +struct iotjs_async_context_s { + napi_env env; + napi_value async_resource; + napi_value async_resource_name; +}; + +#endif // IOTJS_NODE_API_TYPES_H diff --git a/src/iotjs.c b/src/iotjs.c index 7fe8cac671..1c9df6ec12 100644 --- a/src/iotjs.c +++ b/src/iotjs.c @@ -16,66 +16,95 @@ #include "iotjs_def.h" #include "iotjs.h" -#include "iotjs_handlewrap.h" #include "iotjs_js.h" #include "iotjs_string_ext.h" - -#include "jerryscript-debugger.h" -#ifndef __NUTTX__ +#include "jerryscript-ext/debugger.h" +#if ENABLE_MODULE_NAPI +#include "internal/node_api_internal.h" +#endif +#if !defined(__NUTTX__) && !defined(__TIZENRT__) #include "jerryscript-port-default.h" #endif #include "jerryscript-port.h" #include "jerryscript.h" +#include "iotjs_uv_handle.h" + #include +#include #include -/** - * Initialize JerryScript. - */ -static bool iotjs_jerry_initialize(const iotjs_environment_t* env) { +static bool jerry_initialize(iotjs_environment_t* env) { // Set jerry run flags. - uint32_t jerry_flag = JERRY_INIT_EMPTY; + jerry_init_flag_t jerry_flags = JERRY_INIT_EMPTY; if (iotjs_environment_config(env)->memstat) { - jerry_flag |= JERRY_INIT_MEM_STATS; -#ifndef __NUTTX__ + jerry_flags |= JERRY_INIT_MEM_STATS; +#if !defined(__NUTTX__) && !defined(__TIZENRT__) jerry_port_default_set_log_level(JERRY_LOG_LEVEL_DEBUG); #endif } if (iotjs_environment_config(env)->show_opcode) { - jerry_flag |= JERRY_INIT_SHOW_OPCODES; -#ifndef __NUTTX__ + jerry_flags |= JERRY_INIT_SHOW_OPCODES; +#if !defined(__NUTTX__) && !defined(__TIZENRT__) jerry_port_default_set_log_level(JERRY_LOG_LEVEL_DEBUG); #endif } + // Initialize jerry. + jerry_init(jerry_flags); + +#ifdef JERRY_DEBUGGER + if (iotjs_environment_config(env)->debugger != NULL) { + bool protocol_created = false; + char* debug_protocol = iotjs_environment_config(env)->debugger->protocol; + char* debug_channel = iotjs_environment_config(env)->debugger->channel; + + if (!strcmp(debug_protocol, "tcp")) { + uint16_t port = iotjs_environment_config(env)->debugger->port; + protocol_created = jerryx_debugger_tcp_create(port); + } else { + IOTJS_ASSERT(!strcmp(debug_protocol, "serial")); + char* config = iotjs_environment_config(env)->debugger->serial_config; + protocol_created = jerryx_debugger_serial_create(config); + } - if (iotjs_environment_config(env)->debugger) { - jerry_flag |= JERRY_INIT_DEBUGGER; - } + if (!strcmp(debug_channel, "rawpacket")) { + jerryx_debugger_after_connect(protocol_created && + jerryx_debugger_rp_create()); + } else { + IOTJS_ASSERT(!strcmp(debug_channel, "websocket")); + jerryx_debugger_after_connect(protocol_created && + jerryx_debugger_ws_create()); + } - // Initialize jerry. - jerry_init((jerry_init_flag_t)jerry_flag); + if (!jerry_debugger_is_connected()) { + DLOG("jerry debugger connection failed"); + return false; + } - if (iotjs_environment_config(env)->debugger) { jerry_debugger_continue(); } +#endif // Set magic strings. iotjs_register_jerry_magic_string(); + // Register VM execution stop callback. + jerry_set_vm_exec_stop_callback(vm_exec_stop_callback, &env->state, 2); + // Do parse and run to generate initial javascript environment. - jerry_value_t parsed_code = jerry_parse((jerry_char_t*)"", 0, false); - if (jerry_value_has_error_flag(parsed_code)) { + jerry_value_t parsed_code = + jerry_parse(NULL, 0, (jerry_char_t*)"", 0, JERRY_PARSE_NO_OPTS); + if (jerry_value_is_error(parsed_code)) { DLOG("jerry_parse() failed"); jerry_release_value(parsed_code); return false; } jerry_value_t ret_val = jerry_run(parsed_code); - if (jerry_value_has_error_flag(ret_val)) { + if (jerry_value_is_error(ret_val)) { DLOG("jerry_run() failed"); jerry_release_value(parsed_code); jerry_release_value(ret_val); @@ -88,138 +117,218 @@ static bool iotjs_jerry_initialize(const iotjs_environment_t* env) { } -static void iotjs_jerry_release() { - jerry_cleanup(); -} +bool iotjs_initialize(iotjs_environment_t* env) { + // Initialize JerryScript + if (!jerry_initialize(env)) { + DLOG("iotjs_jerry_init failed"); + return false; + } + // Set event loop. + if (!uv_default_loop()) { + DLOG("iotjs uvloop init failed"); + return false; + } + iotjs_environment_set_loop(env, uv_default_loop()); -static bool iotjs_run() { - // Evaluating 'iotjs.js' returns a function. - bool throws = false; -#ifndef ENABLE_SNAPSHOT - iotjs_jval_t jmain = iotjs_jhelper_eval("iotjs.js", strlen("iotjs.js"), - iotjs_s, iotjs_l, false, &throws); -#else - iotjs_jval_t jmain = iotjs_jhelper_exec_snapshot(iotjs_s, iotjs_l, &throws); -#endif + // Bind environment to global object. + const jerry_value_t global = jerry_get_global_object(); + jerry_set_object_native_pointer(global, env, NULL); - if (throws) { - iotjs_uncaught_exception(&jmain); - } + // Initialize builtin process module. + const jerry_value_t process = iotjs_module_get("process"); + iotjs_jval_set_property_jval(global, "process", process); - iotjs_jval_destroy(&jmain); + // Release the global object + jerry_release_value(global); - return !throws; + return true; } -static bool iotjs_start(iotjs_environment_t* env) { - // Initialize commonly used jerry values - iotjs_binding_initialize(); +#ifdef JERRY_DEBUGGER +void iotjs_restart(iotjs_environment_t* env, jerry_value_t jmain) { + jerry_value_t abort_value = jerry_get_value_from_error(jmain, false); + if (jerry_value_is_string(abort_value)) { + /* TODO: When there is an api function to check for reset, + this needs an update. */ + static const char restart_str[] = "r353t"; - // Bind environment to global object. - const iotjs_jval_t* global = iotjs_jval_get_global_object(); - iotjs_jval_set_object_native_handle(global, (uintptr_t)(env), NULL); + jerry_size_t str_size = jerry_get_string_size(abort_value); - // Initialize builtin modules. - iotjs_module_list_init(); + if (str_size == sizeof(restart_str) - 1) { + jerry_char_t str_buf[5]; + jerry_string_to_char_buffer(abort_value, str_buf, str_size); + if (memcmp(restart_str, (char*)(str_buf), str_size) == 0) { + iotjs_environment_config(env)->debugger->context_reset = true; + } + } + } + jerry_release_value(abort_value); +} +#endif - // Initialize builtin process module. - const iotjs_jval_t* process = - iotjs_module_initialize_if_necessary(MODULE_PROCESS); - // Call the entry. - // load and call iotjs.js - iotjs_environment_go_state_running_main(env); +void iotjs_run(iotjs_environment_t* env) { +// Evaluating 'iotjs.js' returns a function. +#ifndef ENABLE_SNAPSHOT + jerry_value_t jmain = iotjs_jhelper_eval("iotjs.js", strlen("iotjs.js"), + iotjs_s, iotjs_l, false); +#else + jerry_value_t jmain = + jerry_exec_snapshot((const uint32_t*)iotjs_js_modules_s, + iotjs_js_modules_l, module_iotjs_idx, + JERRY_SNAPSHOT_EXEC_ALLOW_STATIC); +#endif - iotjs_jval_set_property_jval(global, "process", process); + if (jerry_value_is_error(jmain)) { + jerry_value_t errval = jerry_get_value_from_error(jmain, false); +#ifdef JERRY_DEBUGGER + if (jerry_value_is_abort(jmain) && jerry_value_is_string(errval)) { + static const char restart_str[] = "r353t"; + jerry_size_t str_size = jerry_get_string_size(errval); + + if (str_size == sizeof(restart_str) - 1) { + jerry_char_t str_buf[5]; + jerry_string_to_char_buffer(errval, str_buf, str_size); + if (memcmp(restart_str, (char*)(str_buf), str_size) == 0) { + iotjs_environment_config(env)->debugger->context_reset = true; + } + } + } +#endif - iotjs_run(); + bool throw_exception = !iotjs_environment_is_exiting(env); +#ifdef JERRY_DEBUGGER + throw_exception = throw_exception && + iotjs_environment_config(env)->debugger && + !iotjs_environment_config(env)->debugger->context_reset; +#endif + if (throw_exception) { + iotjs_uncaught_exception(errval); + } - // Run event loop. - iotjs_environment_go_state_running_loop(env); + jerry_release_value(errval); + } - bool more; - do { - more = uv_run(iotjs_environment_loop(env), UV_RUN_ONCE); - more |= iotjs_process_next_tick(); - if (more == false) { - more = uv_loop_alive(iotjs_environment_loop(env)); - } - jerry_value_t ret_val = jerry_run_all_enqueued_jobs(); - if (jerry_value_has_error_flag(ret_val)) { - DLOG("jerry_run_all_enqueued_jobs() failed"); + jerry_release_value(jmain); +} + + +static int iotjs_start(iotjs_environment_t* env) { + iotjs_environment_set_state(env, kRunningMain); +#if ENABLE_MODULE_NAPI + iotjs_setup_napi(); +#endif + // Load and call iotjs.js. + iotjs_run(env); + + int exit_code = 0; + if (!iotjs_environment_is_exiting(env)) { + // Run event loop. + iotjs_environment_set_state(env, kRunningLoop); + + bool more; + do { + more = uv_run(iotjs_environment_loop(env), UV_RUN_ONCE); + more |= iotjs_process_next_tick(); + + jerry_value_t ret_val = jerry_run_all_enqueued_jobs(); + if (jerry_value_is_error(ret_val)) { + ret_val = jerry_get_value_from_error(ret_val, true); + iotjs_uncaught_exception(ret_val); + jerry_release_value(ret_val); + } + + if (more == false) { + more = uv_loop_alive(iotjs_environment_loop(env)); + } + } while (more && !iotjs_environment_is_exiting(env)); + + exit_code = iotjs_process_exitcode(); + + if (!iotjs_environment_is_exiting(env)) { + // Emit 'exit' event. + iotjs_process_emit_exit(exit_code); + + iotjs_environment_set_state(env, kExiting); } - } while (more); + } - iotjs_environment_go_state_exiting(env); + exit_code = iotjs_process_exitcode(); - // Emit 'exit' event. - iotjs_process_emit_exit(0); + return exit_code; +} - // Release builtin modules. - iotjs_module_list_cleanup(); - // Release commonly used jerry values. - iotjs_binding_finalize(); +void iotjs_end(iotjs_environment_t* env) { + uv_loop_t* loop = iotjs_environment_loop(env); + // Close uv loop. + uv_walk(loop, (uv_walk_cb)iotjs_uv_handle_close, NULL); + uv_run(loop, UV_RUN_DEFAULT); - return true; + int res = uv_loop_close(loop); + IOTJS_ASSERT(res == 0); } -static void iotjs_uv_walk_to_close_callback(uv_handle_t* handle, void* arg) { - iotjs_handlewrap_t* handle_wrap = iotjs_handlewrap_from_handle(handle); - IOTJS_ASSERT(handle_wrap != NULL); - - iotjs_handlewrap_close(handle_wrap, NULL); +void iotjs_terminate(iotjs_environment_t* env) { + // Release builtin modules. + iotjs_module_list_cleanup(); +#if ENABLE_MODULE_NAPI + iotjs_cleanup_napi(); +#endif + // Release JerryScript engine. + jerry_cleanup(); } +void iotjs_conf_console_out(int (*out)(int lv, const char* fmt, ...)) { + iotjs_set_console_out(out); +} + int iotjs_entry(int argc, char** argv) { - // Initialize debug print. - init_debug_settings(); + int ret_code = 0; - // Create environment. - iotjs_environment_t* env = (iotjs_environment_t*)iotjs_environment_get(); + // Initialize debug log and environments + iotjs_debuglog_init(); + srand((unsigned)jerry_port_get_current_time()); - // Parse command line arguments. + iotjs_environment_t* env = iotjs_environment_get(); if (!iotjs_environment_parse_command_line_arguments(env, (uint32_t)argc, argv)) { - DLOG("iotjs_environment_parse_command_line_arguments failed"); - return 1; + ret_code = 1; + goto exit; } - // Set event loop. - iotjs_environment_set_loop(env, uv_default_loop()); - - // Initialize JerryScript engine. - if (!iotjs_jerry_initialize(env)) { - DLOG("iotjs_jerry_initialize failed"); - return 1; + // Initialize IoT.js + if (!iotjs_initialize(env)) { + DLOG("iotjs_initialize failed"); + ret_code = 1; + goto terminate; } // Start IoT.js - if (!iotjs_start(env)) { - DLOG("iotjs_start failed"); - return 1; - } + ret_code = iotjs_start(env); - // close uv loop. - // uv_stop(iotjs_environment_loop(env)); - uv_walk(iotjs_environment_loop(env), iotjs_uv_walk_to_close_callback, NULL); - uv_run(iotjs_environment_loop(env), UV_RUN_DEFAULT); + // Ends IoT.js + iotjs_end(env); - int res = uv_loop_close(iotjs_environment_loop(env)); - IOTJS_ASSERT(res == 0); +terminate: + iotjs_terminate(env); - // Release JerryScript engine. - iotjs_jerry_release(); +exit: +#ifdef JERRY_DEBUGGER + if (iotjs_environment_config(env)->debugger && + iotjs_environment_config(env)->debugger->context_reset) { + iotjs_environment_release(); + iotjs_debuglog_release(); - // Release environment. - iotjs_environment_release(); - - // Release debug print setting. - release_debug_settings(); + return iotjs_entry(argc, argv); + } +#endif - return 0; + iotjs_environment_release(); + iotjs_debuglog_release(); + return ret_code; } diff --git a/src/iotjs_binding.c b/src/iotjs_binding.c index 5a5284448e..87d61ffd09 100644 --- a/src/iotjs_binding.c +++ b/src/iotjs_binding.c @@ -16,217 +16,207 @@ #include "iotjs_def.h" #include "iotjs_binding.h" +#include "iotjs_js.h" +#include "modules/iotjs_module_buffer.h" #include -static iotjs_jval_t jundefined; -static iotjs_jval_t jnull; -static iotjs_jval_t jtrue; -static iotjs_jval_t jfalse; -static iotjs_jval_t jglobal; - -static iotjs_jargs_t jargs_empty; - -static jerry_value_t iotjs_jval_as_raw(const iotjs_jval_t* jval); - - -iotjs_jval_t iotjs_jval_create_number(double v) { - iotjs_jval_t jval; - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_jval_t, &jval); - - _this->value = jerry_create_number(v); - return jval; -} - - -iotjs_jval_t iotjs_jval_create_string(const iotjs_string_t* v) { - iotjs_jval_t jval; - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_jval_t, &jval); +jerry_value_t iotjs_jval_create_string(const iotjs_string_t* v) { + jerry_value_t jval; const jerry_char_t* data = (const jerry_char_t*)(iotjs_string_data(v)); jerry_size_t size = iotjs_string_size(v); if (jerry_is_valid_utf8_string(data, size)) { - _this->value = jerry_create_string_sz_from_utf8(data, size); + jval = jerry_create_string_sz_from_utf8(data, size); } else { - _this->value = - jerry_create_error(JERRY_ERROR_TYPE, - (const jerry_char_t*)"Invalid UTF-8 string"); + jval = JS_CREATE_ERROR(TYPE, "Invalid UTF-8 string"); } return jval; } -iotjs_jval_t iotjs_jval_get_string_size(const iotjs_string_t* str) { - iotjs_jval_t str_val = iotjs_jval_create_string(str); - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_jval_t, &str_val); +jerry_value_t iotjs_jval_create_byte_array(uint32_t len, const char* data) { + if (data == NULL) { + len = 0; + } - jerry_size_t size = jerry_get_string_size(_this->value); - iotjs_jval_t jval = iotjs_jval_create_number(size); + jerry_value_t jval = jerry_create_array(len); - iotjs_jval_destroy(&str_val); + for (uint32_t i = 0; i < len; i++) { + jerry_value_t val = jerry_create_number((double)data[i]); + jerry_set_property_by_index(jval, i, val); + jerry_release_value(val); + } return jval; } -iotjs_jval_t iotjs_jval_create_string_raw(const char* data) { - iotjs_jval_t jval; - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_jval_t, &jval); +jerry_value_t iotjs_jval_create_function(jerry_external_handler_t handler) { + jerry_value_t jval = jerry_create_external_function(handler); - _this->value = jerry_create_string((const jerry_char_t*)data); + IOTJS_ASSERT(jerry_value_is_constructor(jval)); return jval; } -iotjs_jval_t iotjs_jval_create_object() { - iotjs_jval_t jval; - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_jval_t, &jval); - - _this->value = jerry_create_object(); - - return jval; +jerry_value_t iotjs_jval_create_error_without_error_flag(const char* msg) { + jerry_value_t jval = + jerry_create_error(JERRY_ERROR_COMMON, (const jerry_char_t*)(msg)); + return jerry_get_value_from_error(jval, true); } -iotjs_jval_t iotjs_jval_create_array(uint32_t len) { - iotjs_jval_t jval; - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_jval_t, &jval); - - _this->value = jerry_create_array(len); - - return jval; +bool iotjs_jval_as_boolean(jerry_value_t jval) { + IOTJS_ASSERT(jerry_value_is_boolean(jval)); + return jerry_get_boolean_value(jval); } -iotjs_jval_t iotjs_jval_create_byte_array(uint32_t len, const char* data) { - iotjs_jval_t jval; - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_jval_t, &jval); +double iotjs_jval_as_number(jerry_value_t jval) { + IOTJS_ASSERT(jerry_value_is_number(jval)); + return jerry_get_number_value(jval); +} - IOTJS_ASSERT(data != NULL); - _this->value = jerry_create_array(len); - for (uint32_t i = 0; i < len; i++) { - jerry_value_t val = jerry_create_number((double)data[i]); - jerry_set_property_by_index(_this->value, i, val); - jerry_release_value(val); +bool iotjs_jbuffer_as_string(jerry_value_t jval, iotjs_string_t* out_string) { + if (out_string == NULL) { + return false; } - return jval; -} - + if (jerry_value_is_string(jval)) { + jerry_size_t size = jerry_get_string_size(jval); -iotjs_jval_t iotjs_jval_create_function(JHandlerType handler) { - iotjs_jval_t jval; - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_jval_t, &jval); + if (size == 0) { + return false; + } - _this->value = jerry_create_external_function(handler); - IOTJS_ASSERT(jerry_value_is_constructor(_this->value)); + char* buffer = iotjs_buffer_allocate(size + 1); + size_t check = + jerry_string_to_char_buffer(jval, (jerry_char_t*)buffer, size); - return jval; -} + IOTJS_ASSERT(check == size); + buffer[size] = '\0'; + *out_string = iotjs_string_create_with_buffer(buffer, size); + return true; + } -iotjs_jval_t iotjs_jval_create_error(const char* msg) { - return iotjs_jval_create_error_type(IOTJS_ERROR_COMMON, msg); -} - + iotjs_bufferwrap_t* buffer_wrap = iotjs_jbuffer_get_bufferwrap_ptr(jval); -iotjs_jval_t iotjs_jval_create_error_type(iotjs_error_t type, const char* msg) { - iotjs_jval_t jval; - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_jval_t, &jval); + if (buffer_wrap == NULL || buffer_wrap->length == 0) { + return false; + } - const jerry_char_t* jmsg = (const jerry_char_t*)(msg); - _this->value = jerry_create_error((jerry_error_t)type, jmsg); - jerry_value_clear_error_flag(&_this->value); + size_t size = buffer_wrap->length; - return jval; + char* buffer = iotjs_buffer_allocate(size + 1); + memcpy(buffer, buffer_wrap->buffer, size); + buffer[size] = '\0'; + *out_string = iotjs_string_create_with_buffer(buffer, size); + return true; } -iotjs_jval_t iotjs_jval_create_copied(const iotjs_jval_t* other) { - iotjs_jval_t jval; - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_jval_t, &jval); - - _this->value = jerry_acquire_value(iotjs_jval_as_raw(other)); - return jval; -} +void iotjs_jval_as_tmp_buffer(jerry_value_t jval, + iotjs_tmp_buffer_t* out_buffer) { + out_buffer->jval = jerry_create_undefined(); + out_buffer->buffer = NULL; + out_buffer->length = 0; + if (jerry_value_is_undefined(jval)) { + return; + } -static iotjs_jval_t iotjs_jval_create_raw(jerry_value_t val) { - iotjs_jval_t jval; - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_jval_t, &jval); + iotjs_bufferwrap_t* buffer_wrap = iotjs_jbuffer_get_bufferwrap_ptr(jval); - _this->value = val; + if (buffer_wrap != NULL) { + IOTJS_ASSERT(buffer_wrap->jobject == jval); - return jval; -} + jerry_acquire_value(jval); + out_buffer->jval = buffer_wrap->jobject; + out_buffer->buffer = buffer_wrap->buffer; + out_buffer->length = buffer_wrap->length; + return; + } + bool was_string = true; -void iotjs_jval_destroy(iotjs_jval_t* jval) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_jval_t, jval); - jerry_release_value(_this->value); -} + if (!jerry_value_is_string(jval)) { + jval = jerry_value_to_string(jval); + if (jerry_value_is_error(jval)) { + out_buffer->jval = jval; + return; + } -static void iotjs_jval_destroy_norelease(iotjs_jval_t* jval) { - IOTJS_VALIDATABLE_STRUCT_DESTRUCTOR_VALIDATE(iotjs_jval_t, jval); -} + was_string = false; + } + jerry_size_t size = jerry_get_string_size(jval); -iotjs_jval_t* iotjs_jval_get_undefined() { - return &jundefined; -} + if (size == 0) { + if (!was_string) { + jerry_release_value(jval); + } + return; + } + char* buffer = iotjs_buffer_allocate(size); + size_t check = jerry_string_to_char_buffer(jval, (jerry_char_t*)buffer, size); -iotjs_jval_t* iotjs_jval_get_null() { - return &jnull; -} + IOTJS_ASSERT(check == size); + out_buffer->buffer = buffer; + out_buffer->length = size; -iotjs_jval_t* iotjs_jval_get_boolean(bool v) { - return v ? &jtrue : &jfalse; + if (!was_string) { + jerry_release_value(jval); + } } -iotjs_jval_t* iotjs_jval_get_global_object() { - return &jglobal; -} - +void iotjs_jval_get_jproperty_as_tmp_buffer(jerry_value_t jobj, + const char* name, + iotjs_tmp_buffer_t* out_buffer) { + jerry_value_t jproperty = iotjs_jval_get_property(jobj, name); -#define TYPE_CHECKER_BODY(jval_type) \ - bool iotjs_jval_is_##jval_type(const iotjs_jval_t* val) { \ - const IOTJS_VALIDATED_STRUCT_METHOD(iotjs_jval_t, val); \ - return jerry_value_is_##jval_type(_this->value); \ + if (jerry_value_is_error(jproperty)) { + out_buffer->jval = jproperty; + out_buffer->buffer = NULL; + out_buffer->length = 0; + return; } -FOR_EACH_JVAL_TYPES(TYPE_CHECKER_BODY) + iotjs_jval_as_tmp_buffer(jproperty, out_buffer); -#undef TYPE_CHECKER_BODY + jerry_release_value(jproperty); +} -bool iotjs_jval_as_boolean(const iotjs_jval_t* jval) { - const IOTJS_VALIDATED_STRUCT_METHOD(iotjs_jval_t, jval); - IOTJS_ASSERT(iotjs_jval_is_boolean(jval)); - return jerry_get_boolean_value(_this->value); -} +void iotjs_free_tmp_buffer(iotjs_tmp_buffer_t* tmp_buffer) { + if (jerry_value_is_undefined(tmp_buffer->jval)) { + if (tmp_buffer->buffer != NULL) { + iotjs_buffer_release(tmp_buffer->buffer); + } + return; + } + IOTJS_ASSERT(!jerry_value_is_error(tmp_buffer->jval) || + tmp_buffer->buffer == NULL); -double iotjs_jval_as_number(const iotjs_jval_t* jval) { - const IOTJS_VALIDATED_STRUCT_METHOD(iotjs_jval_t, jval); - IOTJS_ASSERT(iotjs_jval_is_number(jval)); - return jerry_get_number_value(_this->value); + jerry_release_value(tmp_buffer->jval); } -iotjs_string_t iotjs_jval_as_string(const iotjs_jval_t* jval) { - const IOTJS_VALIDATED_STRUCT_METHOD(iotjs_jval_t, jval); - IOTJS_ASSERT(iotjs_jval_is_string(jval)); +iotjs_string_t iotjs_jval_as_string(jerry_value_t jval) { + IOTJS_ASSERT(jerry_value_is_string(jval)); - jerry_size_t size = jerry_get_string_size(_this->value); + jerry_size_t size = jerry_get_utf8_string_size(jval); if (size == 0) return iotjs_string_create(); @@ -234,7 +224,7 @@ iotjs_string_t iotjs_jval_as_string(const iotjs_jval_t* jval) { char* buffer = iotjs_buffer_allocate(size + 1); jerry_char_t* jerry_buffer = (jerry_char_t*)(buffer); - size_t check = jerry_string_to_char_buffer(_this->value, jerry_buffer, size); + size_t check = jerry_string_to_utf8_char_buffer(jval, jerry_buffer, size); IOTJS_ASSERT(check == size); buffer[size] = '\0'; @@ -245,620 +235,161 @@ iotjs_string_t iotjs_jval_as_string(const iotjs_jval_t* jval) { } -const iotjs_jval_t* iotjs_jval_as_object(const iotjs_jval_t* jval) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jval_t, jval); - IOTJS_ASSERT(iotjs_jval_is_object(jval)); +jerry_value_t iotjs_jval_as_object(jerry_value_t jval) { + IOTJS_ASSERT(jerry_value_is_object(jval)); return jval; } -const iotjs_jval_t* iotjs_jval_as_array(const iotjs_jval_t* jval) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jval_t, jval); - IOTJS_ASSERT(iotjs_jval_is_array(jval)); +jerry_value_t iotjs_jval_as_array(jerry_value_t jval) { + IOTJS_ASSERT(jerry_value_is_array(jval)); return jval; } -const iotjs_jval_t* iotjs_jval_as_function(const iotjs_jval_t* jval) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jval_t, jval); - IOTJS_ASSERT(iotjs_jval_is_function(jval)); +jerry_value_t iotjs_jval_as_function(jerry_value_t jval) { + IOTJS_ASSERT(jerry_value_is_function(jval)); return jval; } -static jerry_value_t iotjs_jval_as_raw(const iotjs_jval_t* jval) { - const IOTJS_VALIDATED_STRUCT_METHOD(iotjs_jval_t, jval); - return _this->value; +bool iotjs_jval_set_prototype(jerry_value_t jobj, jerry_value_t jproto) { + jerry_value_t ret = jerry_set_prototype(jobj, jproto); + bool error_found = jerry_value_is_error(ret); + jerry_release_value(ret); + + return !error_found; } -void iotjs_jval_set_method(const iotjs_jval_t* jobj, const char* name, - iotjs_native_handler_t handler) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jval_t, jobj); - IOTJS_ASSERT(iotjs_jval_is_object(jobj)); +void iotjs_jval_set_method(jerry_value_t jobj, const char* name, + jerry_external_handler_t handler) { + IOTJS_ASSERT(jerry_value_is_object(jobj)); - iotjs_jval_t jfunc = iotjs_jval_create_function_with_dispatch(handler); - iotjs_jval_set_property_jval(jobj, name, &jfunc); - iotjs_jval_destroy(&jfunc); + jerry_value_t jfunc = jerry_create_external_function(handler); + iotjs_jval_set_property_jval(jobj, name, jfunc); + jerry_release_value(jfunc); } -void iotjs_jval_set_property_jval(const iotjs_jval_t* jobj, const char* name, - const iotjs_jval_t* val) { - const IOTJS_VALIDATED_STRUCT_METHOD(iotjs_jval_t, jobj); - IOTJS_ASSERT(iotjs_jval_is_object(jobj)); +void iotjs_jval_set_property_jval(jerry_value_t jobj, const char* name, + jerry_value_t value) { + IOTJS_ASSERT(jerry_value_is_object(jobj)); jerry_value_t prop_name = jerry_create_string((const jerry_char_t*)(name)); - jerry_value_t value = iotjs_jval_as_raw(val); - jerry_value_t ret_val = jerry_set_property(_this->value, prop_name, value); + jerry_value_t ret_val = jerry_set_property(jobj, prop_name, value); jerry_release_value(prop_name); - IOTJS_ASSERT(!jerry_value_has_error_flag(ret_val)); + IOTJS_ASSERT(!jerry_value_is_error(ret_val)); jerry_release_value(ret_val); } -void iotjs_jval_set_property_null(const iotjs_jval_t* jobj, const char* name) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jval_t, jobj); - iotjs_jval_set_property_jval(jobj, name, iotjs_jval_get_null()); +void iotjs_jval_set_property_null(jerry_value_t jobj, const char* name) { + iotjs_jval_set_property_jval(jobj, name, jerry_create_null()); } -void iotjs_jval_set_property_undefined(const iotjs_jval_t* jobj, - const char* name) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jval_t, jobj); - iotjs_jval_set_property_jval(jobj, name, iotjs_jval_get_undefined()); +void iotjs_jval_set_property_undefined(jerry_value_t jobj, const char* name) { + iotjs_jval_set_property_jval(jobj, name, jerry_create_undefined()); } -void iotjs_jval_set_property_boolean(const iotjs_jval_t* jobj, const char* name, +void iotjs_jval_set_property_boolean(jerry_value_t jobj, const char* name, bool v) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jval_t, jobj); - iotjs_jval_set_property_jval(jobj, name, iotjs_jval_get_boolean(v)); + iotjs_jval_set_property_jval(jobj, name, jerry_create_boolean(v)); } -void iotjs_jval_set_property_number(const iotjs_jval_t* jobj, const char* name, +void iotjs_jval_set_property_number(jerry_value_t jobj, const char* name, double v) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jval_t, jobj); - iotjs_jval_t jval = iotjs_jval_create_number(v); - iotjs_jval_set_property_jval(jobj, name, &jval); - iotjs_jval_destroy(&jval); + jerry_value_t jval = jerry_create_number(v); + iotjs_jval_set_property_jval(jobj, name, jval); + jerry_release_value(jval); } -void iotjs_jval_set_property_string(const iotjs_jval_t* jobj, const char* name, +void iotjs_jval_set_property_string(jerry_value_t jobj, const char* name, const iotjs_string_t* v) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jval_t, jobj); - iotjs_jval_t jval = iotjs_jval_create_string(v); - iotjs_jval_set_property_jval(jobj, name, &jval); - iotjs_jval_destroy(&jval); + jerry_value_t jval = iotjs_jval_create_string(v); + iotjs_jval_set_property_jval(jobj, name, jval); + jerry_release_value(jval); } -void iotjs_jval_set_property_string_raw(const iotjs_jval_t* jobj, - const char* name, const char* v) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jval_t, jobj); - iotjs_jval_t jval = iotjs_jval_create_string_raw(v); - iotjs_jval_set_property_jval(jobj, name, &jval); - iotjs_jval_destroy(&jval); +void iotjs_jval_set_property_string_raw(jerry_value_t jobj, const char* name, + const char* v) { + jerry_value_t jval = jerry_create_string((const jerry_char_t*)v); + iotjs_jval_set_property_jval(jobj, name, jval); + jerry_release_value(jval); } -iotjs_jval_t iotjs_jval_get_property(const iotjs_jval_t* jobj, - const char* name) { - const IOTJS_VALIDATED_STRUCT_METHOD(iotjs_jval_t, jobj); - IOTJS_ASSERT(iotjs_jval_is_object(jobj)); +jerry_value_t iotjs_jval_get_property(jerry_value_t jobj, const char* name) { + IOTJS_ASSERT(jerry_value_is_object(jobj)); jerry_value_t prop_name = jerry_create_string((const jerry_char_t*)(name)); - jerry_value_t res = jerry_get_property(_this->value, prop_name); + jerry_value_t res = jerry_get_property(jobj, prop_name); jerry_release_value(prop_name); - if (jerry_value_has_error_flag(res)) { + if (jerry_value_is_error(res)) { jerry_release_value(res); - return iotjs_jval_create_copied(iotjs_jval_get_undefined()); + return jerry_create_undefined(); } - return iotjs_jval_create_raw(res); -} - - -void iotjs_jval_set_object_native_handle(const iotjs_jval_t* jobj, - uintptr_t ptr, - JNativeInfoType native_info) { - const IOTJS_VALIDATED_STRUCT_METHOD(iotjs_jval_t, jobj); - IOTJS_ASSERT(iotjs_jval_is_object(jobj)); - - jerry_set_object_native_pointer(_this->value, (void*)ptr, native_info); -} - - -uintptr_t iotjs_jval_get_object_native_handle(const iotjs_jval_t* jobj) { - const IOTJS_VALIDATED_STRUCT_METHOD(iotjs_jval_t, jobj); - IOTJS_ASSERT(iotjs_jval_is_object(jobj)); - - uintptr_t ptr = 0x0; - JNativeInfoType out_info; - jerry_get_object_native_pointer(_this->value, (void**)&ptr, &out_info); - return ptr; -} - - -uintptr_t iotjs_jval_get_object_from_jhandler(iotjs_jhandler_t* jhandler, - JNativeInfoType native_info) { - const iotjs_jval_t* jobj = JHANDLER_GET_THIS(object); - const IOTJS_DECLARE_THIS(iotjs_jval_t, jobj); - - if (!jerry_value_is_object(_this->value)) { - return 0; - } - - uintptr_t ptr = 0; - JNativeInfoType out_native_info; - - if (jerry_get_object_native_pointer(_this->value, (void**)&ptr, - &out_native_info)) { - if (ptr && out_native_info == native_info) { - return ptr; - } - } - - JHANDLER_THROW(COMMON, "Unsafe access"); - - return 0; + return res; } -void iotjs_jval_set_property_by_index(const iotjs_jval_t* jarr, uint32_t idx, - const iotjs_jval_t* jval) { - const IOTJS_VALIDATED_STRUCT_METHOD(iotjs_jval_t, jarr); - IOTJS_ASSERT(iotjs_jval_is_object(jarr)); +void iotjs_jval_set_property_by_index(jerry_value_t jarr, uint32_t idx, + jerry_value_t jval) { + IOTJS_ASSERT(jerry_value_is_object(jarr)); - jerry_value_t value = iotjs_jval_as_raw(jval); - jerry_value_t ret_val = jerry_set_property_by_index(_this->value, idx, value); - IOTJS_ASSERT(!jerry_value_has_error_flag(ret_val)); + jerry_value_t ret_val = jerry_set_property_by_index(jarr, idx, jval); + IOTJS_ASSERT(!jerry_value_is_error(ret_val)); jerry_release_value(ret_val); } -iotjs_jval_t iotjs_jval_get_property_by_index(const iotjs_jval_t* jarr, - uint32_t idx) { - const IOTJS_VALIDATED_STRUCT_METHOD(iotjs_jval_t, jarr); - IOTJS_ASSERT(iotjs_jval_is_object(jarr)); +jerry_value_t iotjs_jval_get_property_by_index(jerry_value_t jarr, + uint32_t idx) { + IOTJS_ASSERT(jerry_value_is_object(jarr)); - jerry_value_t res = jerry_get_property_by_index(_this->value, idx); + jerry_value_t res = jerry_get_property_by_index(jarr, idx); - if (jerry_value_has_error_flag(res)) { + if (jerry_value_is_error(res)) { jerry_release_value(res); - return iotjs_jval_create_copied(iotjs_jval_get_undefined()); - } - - return iotjs_jval_create_raw(res); -} - - -iotjs_jval_t iotjs_jhelper_call(const iotjs_jval_t* jfunc, - const iotjs_jval_t* jthis, - const iotjs_jargs_t* jargs, bool* throws) { - IOTJS_ASSERT(iotjs_jval_is_object(jfunc)); - - jerry_value_t* jargv_ = NULL; - jerry_length_t jargc_ = iotjs_jargs_length(jargs); - -#ifdef NDEBUG - jargv_ = (jerry_value_t*)jargs->unsafe.argv; -#else - if (jargc_ > 0) { - unsigned buffer_size = sizeof(iotjs_jval_t) * jargc_; - jargv_ = (jerry_value_t*)iotjs_buffer_allocate(buffer_size); - for (unsigned i = 0; i < jargc_; ++i) { - jargv_[i] = iotjs_jval_as_raw(iotjs_jargs_get(jargs, i)); - } - } -#endif - - jerry_value_t jfunc_ = iotjs_jval_as_raw(jfunc); - jerry_value_t jthis_ = iotjs_jval_as_raw(jthis); - jerry_value_t res = jerry_call_function(jfunc_, jthis_, jargv_, jargc_); - -#ifndef NDEBUG - if (jargv_) { - iotjs_buffer_release((char*)jargv_); + return jerry_create_undefined(); } -#endif - - *throws = jerry_value_has_error_flag(res); - - jerry_value_clear_error_flag(&res); - - return iotjs_jval_create_raw(res); -} - -iotjs_jval_t iotjs_jhelper_call_ok(const iotjs_jval_t* jfunc, - const iotjs_jval_t* jthis, - const iotjs_jargs_t* jargs) { - bool throws; - iotjs_jval_t jres = iotjs_jhelper_call(jfunc, jthis, jargs, &throws); - IOTJS_ASSERT(!throws); - return jres; + return res; } -iotjs_jval_t iotjs_jhelper_eval(const char* name, size_t name_len, - const uint8_t* data, size_t size, - bool strict_mode, bool* throws) { - jerry_value_t res = - jerry_parse_named_resource((const jerry_char_t*)name, name_len, - (const jerry_char_t*)data, size, strict_mode); +jerry_value_t iotjs_jhelper_eval(const char* name, size_t name_len, + const uint8_t* data, size_t size, + bool strict_mode) { + uint32_t opts = strict_mode ? JERRY_PARSE_STRICT_MODE : JERRY_PARSE_NO_OPTS; - *throws = jerry_value_has_error_flag(res); + jerry_value_t jres = jerry_parse((const jerry_char_t*)name, name_len, + (const jerry_char_t*)data, size, opts); - if (!*throws) { - jerry_value_t func = res; - res = jerry_run(func); + if (!jerry_value_is_error(jres)) { + jerry_value_t func = jres; + jres = jerry_run(func); jerry_release_value(func); - - *throws = jerry_value_has_error_flag(res); } - jerry_value_clear_error_flag(&res); - - return iotjs_jval_create_raw(res); -} - - -#ifdef ENABLE_SNAPSHOT -iotjs_jval_t iotjs_jhelper_exec_snapshot(const void* snapshot_p, - size_t snapshot_size, bool* throws) { - jerry_value_t res = jerry_exec_snapshot(snapshot_p, snapshot_size, false); - /* the snapshot buffer can be referenced - * until jerry_cleanup is not called */ - - *throws = jerry_value_has_error_flag(res); - - jerry_value_clear_error_flag(&res); - - return iotjs_jval_create_raw(res); -} -#endif - - -iotjs_jargs_t iotjs_jargs_create(uint16_t capacity) { - iotjs_jargs_t jargs; - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_jargs_t, &jargs); - - _this->capacity = capacity; - _this->argc = 0; - if (capacity > 0) { - unsigned buffer_size = sizeof(iotjs_jval_t) * capacity; - _this->argv = (iotjs_jval_t*)iotjs_buffer_allocate(buffer_size); - } else { - return jargs_empty; - } - - return jargs; -} - - -static void iotjs_jargs_initialize_empty(iotjs_jargs_t* jargs) { - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_jargs_t, jargs); - _this->capacity = 0; - _this->argc = 0; - _this->argv = NULL; -} - - -const iotjs_jargs_t* iotjs_jargs_get_empty() { - return &jargs_empty; -} - - -void iotjs_jargs_destroy(iotjs_jargs_t* jargs) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_jargs_t, jargs); - - IOTJS_ASSERT(_this->argv == NULL || _this->argc > 0); - IOTJS_ASSERT(_this->argc <= _this->capacity); - - if (_this->capacity > 0) { - for (unsigned i = 0; i < _this->argc; ++i) { - iotjs_jval_destroy(&_this->argv[i]); - } - iotjs_buffer_release((char*)_this->argv); - } else { - IOTJS_ASSERT(_this->argv == NULL); - } -} - - -uint16_t iotjs_jargs_length(const iotjs_jargs_t* jargs) { - const IOTJS_VALIDATED_STRUCT_METHOD(iotjs_jargs_t, jargs); - return _this->argc; -} - - -void iotjs_jargs_append_jval(iotjs_jargs_t* jargs, const iotjs_jval_t* x) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_jargs_t, jargs); - IOTJS_ASSERT(_this->argc < _this->capacity); - _this->argv[_this->argc++] = iotjs_jval_create_copied(x); -} - - -void iotjs_jargs_append_undefined(iotjs_jargs_t* jargs) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jargs_t, jargs); - iotjs_jargs_append_jval(jargs, iotjs_jval_get_undefined()); -} - - -void iotjs_jargs_append_null(iotjs_jargs_t* jargs) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jargs_t, jargs); - iotjs_jargs_append_jval(jargs, iotjs_jval_get_null()); -} - - -void iotjs_jargs_append_bool(iotjs_jargs_t* jargs, bool x) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jargs_t, jargs); - iotjs_jargs_append_jval(jargs, iotjs_jval_get_boolean(x)); -} - - -void iotjs_jargs_append_number(iotjs_jargs_t* jargs, double x) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jargs_t, jargs); - iotjs_jval_t jval = iotjs_jval_create_number(x); - iotjs_jargs_append_jval(jargs, &jval); - iotjs_jval_destroy(&jval); -} - - -void iotjs_jargs_append_string(iotjs_jargs_t* jargs, const iotjs_string_t* x) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jargs_t, jargs); - iotjs_jval_t jval = iotjs_jval_create_string(x); - iotjs_jargs_append_jval(jargs, &jval); - iotjs_jval_destroy(&jval); -} - - -void iotjs_jargs_append_error(iotjs_jargs_t* jargs, const char* msg) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jargs_t, jargs); - iotjs_jval_t error = iotjs_jval_create_error(msg); - iotjs_jargs_append_jval(jargs, &error); - iotjs_jval_destroy(&error); -} - - -void iotjs_jargs_append_string_raw(iotjs_jargs_t* jargs, const char* x) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jargs_t, jargs); - iotjs_jval_t jval = iotjs_jval_create_string_raw(x); - iotjs_jargs_append_jval(jargs, &jval); - iotjs_jval_destroy(&jval); -} - - -void iotjs_jargs_replace(iotjs_jargs_t* jargs, uint16_t index, - const iotjs_jval_t* x) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_jargs_t, jargs); - - IOTJS_ASSERT(index < _this->argc); - - iotjs_jval_destroy(&_this->argv[index]); - _this->argv[index] = iotjs_jval_create_copied(x); -} - - -const iotjs_jval_t* iotjs_jargs_get(const iotjs_jargs_t* jargs, - uint16_t index) { - const IOTJS_VALIDATED_STRUCT_METHOD(iotjs_jargs_t, jargs); - - IOTJS_ASSERT(index < _this->argc); - return &_this->argv[index]; -} - - -void iotjs_jhandler_initialize(iotjs_jhandler_t* jhandler, - const jerry_value_t jfunc, - const jerry_value_t jthis, - const jerry_value_t jargv[], - const uint16_t jargc) { - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_jhandler_t, jhandler); - - _this->jfunc = iotjs_jval_create_raw(jfunc); - _this->jthis = iotjs_jval_create_raw(jthis); - _this->jret = iotjs_jval_create_copied(iotjs_jval_get_undefined()); -#ifdef NDEBUG - _this->jargv = (iotjs_jval_t*)jargv; -#else - if (jargc > 0) { - unsigned buffer_size = sizeof(iotjs_jval_t) * jargc; - _this->jargv = (iotjs_jval_t*)iotjs_buffer_allocate(buffer_size); - for (int i = 0; i < jargc; ++i) { - _this->jargv[i] = iotjs_jval_create_raw(jargv[i]); - } - } else { - _this->jargv = NULL; - } - _this->finished = false; -#endif - - _this->jargc = jargc; -} - - -void iotjs_jhandler_destroy(iotjs_jhandler_t* jhandler) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_jhandler_t, jhandler); - iotjs_jval_destroy_norelease(&_this->jfunc); - iotjs_jval_destroy_norelease(&_this->jthis); - iotjs_jval_destroy_norelease(&_this->jret); -#ifndef NDEBUG - if (_this->jargc > 0) { - for (int i = 0; i < _this->jargc; ++i) { - iotjs_jval_destroy_norelease(&_this->jargv[i]); - } - iotjs_buffer_release((char*)(_this->jargv)); - } else { - IOTJS_ASSERT(_this->jargv == NULL); - } -#endif -} - - -const iotjs_jval_t* iotjs_jhandler_get_function(iotjs_jhandler_t* jhandler) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_jhandler_t, jhandler); - return &_this->jfunc; -} - - -const iotjs_jval_t* iotjs_jhandler_get_this(iotjs_jhandler_t* jhandler) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_jhandler_t, jhandler); - return &_this->jthis; -} - - -const iotjs_jval_t* iotjs_jhandler_get_arg(iotjs_jhandler_t* jhandler, - uint16_t index) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_jhandler_t, jhandler); - IOTJS_ASSERT(index < _this->jargc); - return &_this->jargv[index]; -} - - -uint16_t iotjs_jhandler_get_arg_length(iotjs_jhandler_t* jhandler) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_jhandler_t, jhandler); - return _this->jargc; -} - - -void iotjs_jhandler_return_jval(iotjs_jhandler_t* jhandler, - const iotjs_jval_t* ret) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_jhandler_t, jhandler); - -#ifndef NDEBUG - IOTJS_ASSERT(_this->finished == false); -#endif - - iotjs_jval_destroy(&_this->jret); - _this->jret = iotjs_jval_create_copied(ret); -#ifndef NDEBUG - _this->finished = true; -#endif -} - - -void iotjs_jhandler_return_undefined(iotjs_jhandler_t* jhandler) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jhandler_t, jhandler); - iotjs_jhandler_return_jval(jhandler, iotjs_jval_get_undefined()); -} - - -void iotjs_jhandler_return_null(iotjs_jhandler_t* jhandler) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jhandler_t, jhandler); - iotjs_jhandler_return_jval(jhandler, iotjs_jval_get_null()); -} - - -void iotjs_jhandler_return_boolean(iotjs_jhandler_t* jhandler, bool ret) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jhandler_t, jhandler); - iotjs_jhandler_return_jval(jhandler, iotjs_jval_get_boolean(ret)); -} - - -void iotjs_jhandler_return_number(iotjs_jhandler_t* jhandler, double ret) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jhandler_t, jhandler); - iotjs_jval_t jval = iotjs_jval_create_number(ret); - iotjs_jhandler_return_jval(jhandler, &jval); - iotjs_jval_destroy(&jval); -} - - -void iotjs_jhandler_return_string(iotjs_jhandler_t* jhandler, - const iotjs_string_t* ret) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jhandler_t, jhandler); - iotjs_jval_t jval = iotjs_jval_create_string(ret); - iotjs_jhandler_return_jval(jhandler, &jval); - iotjs_jval_destroy(&jval); -} - - -void iotjs_jhandler_return_string_raw(iotjs_jhandler_t* jhandler, - const char* ret) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jhandler_t, jhandler); - iotjs_jval_t jval = iotjs_jval_create_string_raw(ret); - iotjs_jhandler_return_jval(jhandler, &jval); - iotjs_jval_destroy(&jval); -} - - -void iotjs_jhandler_throw(iotjs_jhandler_t* jhandler, const iotjs_jval_t* err) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_jhandler_t, jhandler); -#ifndef NDEBUG - IOTJS_ASSERT(_this->finished == false); -#endif - - iotjs_jval_destroy(&_this->jret); - _this->jret = iotjs_jval_create_copied(err); - jerry_value_set_error_flag(&_this->jret.unsafe.value); - -#ifndef NDEBUG - _this->finished = true; -#endif + return jres; } -static jerry_value_t iotjs_native_dispatch_function( - const jerry_value_t jfunc, const jerry_value_t jthis, - const jerry_value_t jargv[], const JRawLengthType jargc) { - uintptr_t target_function_ptr = 0x0; - JNativeInfoType out_info; +jerry_value_t vm_exec_stop_callback(void* user_p) { + State* state_p = (State*)user_p; - if (!jerry_get_object_native_pointer(jfunc, (void**)&target_function_ptr, - &out_info)) { - const jerry_char_t* jmsg = (const jerry_char_t*)("Internal dispatch error"); - return jerry_create_error((jerry_error_t)IOTJS_ERROR_COMMON, jmsg); + if (*state_p != kExiting) { + return jerry_create_undefined(); } - IOTJS_ASSERT(target_function_ptr != 0x0); - - iotjs_jhandler_t jhandler; - iotjs_jhandler_initialize(&jhandler, jfunc, jthis, jargv, jargc); - - ((iotjs_native_handler_t)target_function_ptr)(&jhandler); - - jerry_value_t ret_val = jhandler.unsafe.jret.unsafe.value; - iotjs_jhandler_destroy(&jhandler); - return ret_val; -} - - -iotjs_jval_t iotjs_jval_create_function_with_dispatch( - iotjs_native_handler_t handler) { - iotjs_jval_t jfunc = - iotjs_jval_create_function(iotjs_native_dispatch_function); - iotjs_jval_set_object_native_handle(&jfunc, (uintptr_t)handler, NULL); - return jfunc; -} - - -void iotjs_binding_initialize() { - jundefined = iotjs_jval_create_raw(jerry_create_undefined()); - jnull = iotjs_jval_create_raw(jerry_create_null()); - jtrue = iotjs_jval_create_raw(jerry_create_boolean(true)); - jfalse = iotjs_jval_create_raw(jerry_create_boolean(false)); - jglobal = iotjs_jval_create_raw(jerry_get_global_object()); - - IOTJS_ASSERT(iotjs_jval_is_object(&jglobal)); - - iotjs_jargs_initialize_empty(&jargs_empty); - -#ifdef NDEBUG - assert(sizeof(iotjs_jval_t) == sizeof(jerry_value_t)); -#endif -} - - -void iotjs_binding_finalize() { - iotjs_jval_destroy(&jundefined); - iotjs_jval_destroy(&jnull); - iotjs_jval_destroy(&jtrue); - iotjs_jval_destroy(&jfalse); - iotjs_jval_destroy(&jglobal); - iotjs_jargs_destroy(&jargs_empty); + return jerry_create_string((const jerry_char_t*)"Abort script"); } diff --git a/src/iotjs_binding.h b/src/iotjs_binding.h index 3b3c4bed32..9c91f6424d 100644 --- a/src/iotjs_binding.h +++ b/src/iotjs_binding.h @@ -22,302 +22,191 @@ #include -typedef jerry_external_handler_t JHandlerType; -typedef const jerry_object_native_info_t* JNativeInfoType; -typedef jerry_length_t JRawLengthType; +typedef const jerry_object_native_info_t JNativeInfoType; +/* Constructors */ +jerry_value_t iotjs_jval_create_string(const iotjs_string_t* v); +jerry_value_t iotjs_jval_create_byte_array(uint32_t len, const char* data); +jerry_value_t iotjs_jval_create_function(jerry_external_handler_t handler); +jerry_value_t iotjs_jval_create_error_without_error_flag(const char* msg); -typedef enum { - IOTJS_ERROR_COMMON = JERRY_ERROR_COMMON, - IOTJS_ERROR_EVAL = JERRY_ERROR_EVAL, - IOTJS_ERROR_RANGE = JERRY_ERROR_RANGE, - IOTJS_ERROR_REFERENCE = JERRY_ERROR_REFERENCE, - IOTJS_ERROR_SYNTAX = JERRY_ERROR_SYNTAX, - IOTJS_ERROR_TYPE = JERRY_ERROR_TYPE, - IOTJS_ERROR_URI = JERRY_ERROR_URI -} iotjs_error_t; - - -#define FOR_EACH_JVAL_TYPES(F) \ - F(undefined) \ - F(null) \ - F(boolean) \ - F(number) \ - F(string) \ - F(object) \ - F(array) \ - F(function) - +/* Type Converters */ +bool iotjs_jval_as_boolean(jerry_value_t); +double iotjs_jval_as_number(jerry_value_t); +iotjs_string_t iotjs_jval_as_string(jerry_value_t); +jerry_value_t iotjs_jval_as_object(jerry_value_t); +jerry_value_t iotjs_jval_as_array(jerry_value_t); +jerry_value_t iotjs_jval_as_function(jerry_value_t); +bool iotjs_jbuffer_as_string(jerry_value_t jval, iotjs_string_t* out_string); -typedef struct { - jerry_value_t value; // JavaScript value representation -} IOTJS_VALIDATED_STRUCT(iotjs_jval_t); +/* Temporary Buffers for JavaScript Values */ typedef struct { - iotjs_jval_t jfunc; - iotjs_jval_t jthis; - iotjs_jval_t* jargv; - iotjs_jval_t jret; - uint16_t jargc; -#ifndef NDEBUG - bool finished; -#endif -} IOTJS_VALIDATED_STRUCT(iotjs_jhandler_t); - -typedef void (*iotjs_native_handler_t)(iotjs_jhandler_t* jhandler); - - -/* Constructors */ -iotjs_jval_t iotjs_jval_create_number(double v); -iotjs_jval_t iotjs_jval_create_string(const iotjs_string_t* v); -iotjs_jval_t iotjs_jval_create_string_raw(const char* data); -iotjs_jval_t iotjs_jval_create_object(); -iotjs_jval_t iotjs_jval_create_array(uint32_t len); -iotjs_jval_t iotjs_jval_create_byte_array(uint32_t len, const char* data); -iotjs_jval_t iotjs_jval_create_function(JHandlerType handler); -iotjs_jval_t iotjs_jval_create_error(const char* msg); -iotjs_jval_t iotjs_jval_create_error_type(iotjs_error_t type, const char* msg); -iotjs_jval_t iotjs_jval_create_copied(const iotjs_jval_t* other); - -iotjs_jval_t iotjs_jval_get_string_size(const iotjs_string_t* str); - -iotjs_jval_t* iotjs_jval_get_undefined(); -iotjs_jval_t* iotjs_jval_get_null(); -iotjs_jval_t* iotjs_jval_get_boolean(bool v); -iotjs_jval_t* iotjs_jval_get_global_object(); - -/* Destructor */ -void iotjs_jval_destroy(iotjs_jval_t* jval); - -#define THIS_JVAL const iotjs_jval_t* jval - -/* Type Checkers */ -bool iotjs_jval_is_undefined(THIS_JVAL); -bool iotjs_jval_is_null(THIS_JVAL); -bool iotjs_jval_is_boolean(THIS_JVAL); -bool iotjs_jval_is_number(THIS_JVAL); -bool iotjs_jval_is_string(THIS_JVAL); -bool iotjs_jval_is_object(THIS_JVAL); -bool iotjs_jval_is_array(THIS_JVAL); -bool iotjs_jval_is_function(THIS_JVAL); - -/* Type Converters */ -bool iotjs_jval_as_boolean(THIS_JVAL); -double iotjs_jval_as_number(THIS_JVAL); -iotjs_string_t iotjs_jval_as_string(THIS_JVAL); -const iotjs_jval_t* iotjs_jval_as_object(THIS_JVAL); -const iotjs_jval_t* iotjs_jval_as_array(THIS_JVAL); -const iotjs_jval_t* iotjs_jval_as_function(THIS_JVAL); + jerry_value_t jval; + char* buffer; + size_t length; +} iotjs_tmp_buffer_t; + +void iotjs_jval_as_tmp_buffer(jerry_value_t jval, + iotjs_tmp_buffer_t* out_buffer); +void iotjs_jval_get_jproperty_as_tmp_buffer(jerry_value_t jobj, + const char* name, + iotjs_tmp_buffer_t* out_buffer); +void iotjs_free_tmp_buffer(iotjs_tmp_buffer_t* tmp_buffer); /* Methods for General JavaScript Object */ -void iotjs_jval_set_method(THIS_JVAL, const char* name, - iotjs_native_handler_t handler); -void iotjs_jval_set_property_jval(THIS_JVAL, const char* name, - const iotjs_jval_t* value); -void iotjs_jval_set_property_null(THIS_JVAL, const char* name); -void iotjs_jval_set_property_undefined(THIS_JVAL, const char* name); -void iotjs_jval_set_property_boolean(THIS_JVAL, const char* name, bool v); -void iotjs_jval_set_property_number(THIS_JVAL, const char* name, double v); -void iotjs_jval_set_property_string(THIS_JVAL, const char* name, +void iotjs_jval_set_method(jerry_value_t jobj, const char* name, + jerry_external_handler_t handler); +bool iotjs_jval_set_prototype(jerry_value_t jobj, jerry_value_t jproto); +void iotjs_jval_set_property_jval(jerry_value_t jobj, const char* name, + jerry_value_t value); +void iotjs_jval_set_property_null(jerry_value_t jobj, const char* name); +void iotjs_jval_set_property_undefined(jerry_value_t jobj, const char* name); +void iotjs_jval_set_property_boolean(jerry_value_t jobj, const char* name, + bool v); +void iotjs_jval_set_property_number(jerry_value_t jobj, const char* name, + double v); +void iotjs_jval_set_property_string(jerry_value_t jobj, const char* name, const iotjs_string_t* v); -void iotjs_jval_set_property_string_raw(THIS_JVAL, const char* name, +void iotjs_jval_set_property_string_raw(jerry_value_t jobj, const char* name, const char* v); -iotjs_jval_t iotjs_jval_get_property(THIS_JVAL, const char* name); - -void iotjs_jval_set_object_native_handle(THIS_JVAL, uintptr_t ptr, - JNativeInfoType native_info); -uintptr_t iotjs_jval_get_object_native_handle(THIS_JVAL); -uintptr_t iotjs_jval_get_object_from_jhandler(iotjs_jhandler_t* jhandler, - JNativeInfoType native_info); - -void iotjs_jval_set_property_by_index(THIS_JVAL, uint32_t idx, - const iotjs_jval_t* value); -iotjs_jval_t iotjs_jval_get_property_by_index(THIS_JVAL, uint32_t idx); - - -#undef THIS_JVAL - - -typedef struct { - uint16_t capacity; - uint16_t argc; - iotjs_jval_t* argv; -} IOTJS_VALIDATED_STRUCT(iotjs_jargs_t); - - -iotjs_jargs_t iotjs_jargs_create(uint16_t capacity); - -const iotjs_jargs_t* iotjs_jargs_get_empty(); - -void iotjs_jargs_destroy(iotjs_jargs_t* jargs); - -uint16_t iotjs_jargs_length(const iotjs_jargs_t* jargs); - -void iotjs_jargs_append_jval(iotjs_jargs_t* jargs, const iotjs_jval_t* x); -void iotjs_jargs_append_undefined(iotjs_jargs_t* jargs); -void iotjs_jargs_append_null(iotjs_jargs_t* jargs); -void iotjs_jargs_append_bool(iotjs_jargs_t* jargs, bool x); -void iotjs_jargs_append_number(iotjs_jargs_t* jargs, double x); -void iotjs_jargs_append_string(iotjs_jargs_t* jargs, const iotjs_string_t* x); -void iotjs_jargs_append_string_raw(iotjs_jargs_t* jargs, const char* x); -void iotjs_jargs_append_error(iotjs_jargs_t* jargs, const char* msg); - - -void iotjs_jargs_replace(iotjs_jargs_t* jargs, uint16_t index, - const iotjs_jval_t* x); - -const iotjs_jval_t* iotjs_jargs_get(const iotjs_jargs_t* jargs, uint16_t index); +jerry_value_t iotjs_jval_get_property(jerry_value_t jobj, const char* name); - -// Calls JavaScript function. -iotjs_jval_t iotjs_jhelper_call(const iotjs_jval_t* jfunc, - const iotjs_jval_t* jthis, - const iotjs_jargs_t* jargs, bool* throws); - -// Calls javascript function. -iotjs_jval_t iotjs_jhelper_call_ok(const iotjs_jval_t* jfunc, - const iotjs_jval_t* jthis, - const iotjs_jargs_t* jargs); +void iotjs_jval_set_property_by_index(jerry_value_t jarr, uint32_t idx, + jerry_value_t jval); +jerry_value_t iotjs_jval_get_property_by_index(jerry_value_t jarr, + uint32_t idx); // Evaluates javascript source file. -iotjs_jval_t iotjs_jhelper_eval(const char* name, size_t name_len, - const uint8_t* data, size_t size, - bool strict_mode, bool* throws); -#ifdef ENABLE_SNAPSHOT -// Evaluates javascript snapshot. -iotjs_jval_t iotjs_jhelper_exec_snapshot(const void* snapshot_p, - size_t snapshot_size, bool* throws); -#endif +jerry_value_t iotjs_jhelper_eval(const char* name, size_t name_len, + const uint8_t* data, size_t size, + bool strict_mode); + +/* Note: + * Defines started with underscores should not be used + * outside of this header. + */ +#define JS_CREATE_ERROR(TYPE, message) \ + jerry_create_error(JERRY_ERROR_##TYPE, (const jerry_char_t*)message) +#define jerry_value_is_any(value) true +#define iotjs_jval_as_any(value) (value) -void iotjs_jhandler_initialize(iotjs_jhandler_t* jhandler, - const jerry_value_t jfunc, - const jerry_value_t jthis, - const jerry_value_t jargv[], - const uint16_t jargc); - -void iotjs_jhandler_destroy(iotjs_jhandler_t* jhandler); - -const iotjs_jval_t* iotjs_jhandler_get_function(iotjs_jhandler_t* jhandler); -const iotjs_jval_t* iotjs_jhandler_get_this(iotjs_jhandler_t* jhandler); -const iotjs_jval_t* iotjs_jhandler_get_arg(iotjs_jhandler_t* jhandler, - uint16_t index); -uint16_t iotjs_jhandler_get_arg_length(iotjs_jhandler_t* jhandler); - -void iotjs_jhandler_return_jval(iotjs_jhandler_t* jhandler, - const iotjs_jval_t* ret); -void iotjs_jhandler_return_undefined(iotjs_jhandler_t* jhandler); -void iotjs_jhandler_return_null(iotjs_jhandler_t* jhandler); -void iotjs_jhandler_return_boolean(iotjs_jhandler_t* jhandler, bool x); -void iotjs_jhandler_return_number(iotjs_jhandler_t* jhandler, double x); -void iotjs_jhandler_return_string(iotjs_jhandler_t* jhandler, - const iotjs_string_t* x); -void iotjs_jhandler_return_string_raw(iotjs_jhandler_t* jhandler, - const char* x); - -void iotjs_jhandler_throw(iotjs_jhandler_t* jhandler, const iotjs_jval_t* err); - -iotjs_jval_t iotjs_jval_create_function_with_dispatch( - iotjs_native_handler_t handler); - - -#define JHANDLER_THROW(TYPE, message) \ - iotjs_jval_t e = iotjs_jval_create_error_type(IOTJS_ERROR_##TYPE, message); \ - iotjs_jhandler_throw(jhandler, &e); \ - iotjs_jval_destroy(&e); - -#define JHANDLER_CHECK(predicate) \ - if (!(predicate)) { \ - char buffer[64]; \ - snprintf(buffer, 63, "Internal error (%s)", __func__); \ - JHANDLER_THROW(COMMON, buffer) \ - return; \ +#define JS_CHECK(predicate) \ + if (!(predicate)) { \ + return JS_CREATE_ERROR(COMMON, "Internal error"); \ } -#define JHANDLER_CHECK_TYPE(jval, type) \ - JHANDLER_CHECK(iotjs_jval_is_##type(jval)); +#define __JS_CHECK_TYPE(index, type) jerry_value_is_##type(jargv[index]) -#define JHANDLER_CHECK_ARG(index, type) \ - JHANDLER_CHECK_TYPE(iotjs_jhandler_get_arg(jhandler, index), type); +#define JS_CHECK_ARG(index, type) JS_CHECK(__JS_CHECK_TYPE(index, type)) -#define JHANDLER_CHECK_ARG_IF_EXIST(index, type) \ - if (iotjs_jhandler_get_arg_length(jhandler) > index) { \ - JHANDLER_CHECK_TYPE(iotjs_jhandler_get_arg(jhandler, index), type); \ +#define JS_CHECK_ARG_IF_EXIST(index, type) \ + if (jargc > index) { \ + JS_CHECK(__JS_CHECK_TYPE(index, type)) \ } -#define JHANDLER_CHECK_ARGS_0() +#define JS_CHECK_ARGS_0() -#define JHANDLER_CHECK_ARGS_1(type0) \ - JHANDLER_CHECK_ARGS_0(); \ - JHANDLER_CHECK_ARG(0, type0); +#define JS_CHECK_ARGS_1(type0) \ + JS_CHECK_ARGS_0() \ + __JS_CHECK_TYPE(0, type0) -#define JHANDLER_CHECK_ARGS_2(type0, type1) \ - JHANDLER_CHECK_ARGS_1(type0); \ - JHANDLER_CHECK_ARG(1, type1); +#define JS_CHECK_ARGS_2(type0, type1) \ + JS_CHECK_ARGS_1(type0) \ + &&__JS_CHECK_TYPE(1, type1) -#define JHANDLER_CHECK_ARGS_3(type0, type1, type2) \ - JHANDLER_CHECK_ARGS_2(type0, type1); \ - JHANDLER_CHECK_ARG(2, type2); +#define JS_CHECK_ARGS_3(type0, type1, type2) \ + JS_CHECK_ARGS_2(type0, type1) \ + &&__JS_CHECK_TYPE(2, type2) -#define JHANDLER_CHECK_ARGS_4(type0, type1, type2, type3) \ - JHANDLER_CHECK_ARGS_3(type0, type1, type2); \ - JHANDLER_CHECK_ARG(3, type3); +#define JS_CHECK_ARGS_4(type0, type1, type2, type3) \ + JS_CHECK_ARGS_3(type0, type1, type2) \ + &&__JS_CHECK_TYPE(3, type3) -#define JHANDLER_CHECK_ARGS_5(type0, type1, type2, type3, type4) \ - JHANDLER_CHECK_ARGS_4(type0, type1, type2, type3); \ - JHANDLER_CHECK_ARG(4, type4); +#define JS_CHECK_ARGS_5(type0, type1, type2, type3, type4) \ + JS_CHECK_ARGS_4(type0, type1, type2, type3) \ + &&__JS_CHECK_TYPE(4, type4) -// Workaround for GCC type-limits warning -static inline bool ge(uint16_t a, uint16_t b) { - return a >= b; -} +#define JS_CHECK_ARGS(argc, ...) \ + JS_CHECK(jargc >= argc && JS_CHECK_ARGS_##argc(__VA_ARGS__)) -#define JHANDLER_CHECK_ARGS(argc, ...) \ - JHANDLER_CHECK(ge(iotjs_jhandler_get_arg_length(jhandler), argc)); \ - JHANDLER_CHECK_ARGS_##argc(__VA_ARGS__) +#define JS_CHECK_THIS() JS_CHECK(jerry_value_is_object(jthis)) -#define JHANDLER_CHECK_THIS(type) \ - JHANDLER_CHECK_TYPE(iotjs_jhandler_get_this(jhandler), type); +#define JS_GET_ARG(index, type) iotjs_jval_as_##type(jargv[index]) -#define JHANDLER_GET_ARG(index, type) \ - iotjs_jval_as_##type(iotjs_jhandler_get_arg(jhandler, index)) +#define JS_GET_ARG_IF_EXIST(index, type) \ + ((jargc > index) && jerry_value_is_##type(jargv[index]) \ + ? jargv[index] \ + : jerry_create_null()) -#define JHANDLER_GET_ARG_IF_EXIST(index, type) \ - ((iotjs_jhandler_get_arg_length(jhandler) > index) \ - ? (iotjs_jval_is_##type(iotjs_jhandler_get_arg(jhandler, index)) \ - ? iotjs_jhandler_get_arg(jhandler, index) \ - : NULL) \ - : NULL) +#define JS_GET_THIS() iotjs_jval_as_object(jthis) -#define JHANDLER_GET_THIS(type) \ - iotjs_jval_as_##type(iotjs_jhandler_get_this(jhandler)) - -#define JHANDLER_FUNCTION(name) static void name(iotjs_jhandler_t* jhandler) +#define JS_FUNCTION(name) \ + static jerry_value_t name(const jerry_value_t jfunc, \ + const jerry_value_t jthis, \ + const jerry_value_t jargv[], \ + const jerry_length_t jargc) #if defined(EXPERIMENTAL) && !defined(DEBUG) // This code branch is to be in #ifdef NDEBUG -#define DJHANDLER_CHECK_ARG(index, type) ((void)0) -#define DJHANDLER_CHECK_ARGS(argc, ...) ((void)0) -#define DJHANDLER_CHECK_THIS(type) ((void)0) -#define DJHANDLER_CHECK_ARG_IF_EXIST(index, type) ((void)0) +#define DJS_CHECK(predicate) ((void)0) +#define DJS_CHECK_ARG(index, type) ((void)0) +#define DJS_CHECK_ARGS(argc, ...) ((void)0) +#define DJS_CHECK_THIS() ((void)0) +#define DJS_CHECK_ARG_IF_EXIST(index, type) ((void)0) #else -#define DJHANDLER_CHECK_ARG(index, type) JHANDLER_CHECK_ARG(index, type) -#define DJHANDLER_CHECK_ARGS(argc, ...) JHANDLER_CHECK_ARGS(argc, __VA_ARGS__) -#define DJHANDLER_CHECK_THIS(type) JHANDLER_CHECK_THIS(type) -#define DJHANDLER_CHECK_ARG_IF_EXIST(index, type) \ - JHANDLER_CHECK_ARG_IF_EXIST(index, type) +#define DJS_CHECK(predicate) JS_CHECK(predicate) +#define DJS_CHECK_ARG(index, type) JS_CHECK_ARG(index, type) +#define DJS_CHECK_ARGS(argc, ...) JS_CHECK_ARGS(argc, __VA_ARGS__) +#define DJS_CHECK_THIS() JS_CHECK_THIS() +#define DJS_CHECK_ARG_IF_EXIST(index, type) JS_CHECK_ARG_IF_EXIST(index, type) #endif -#define JHANDLER_DECLARE_THIS_PTR(type, name) \ - iotjs_##type##_t* name = (iotjs_##type##_t*) \ - iotjs_jval_get_object_from_jhandler(jhandler, &this_module_native_info); \ - if (!name) { \ - return; \ - } - -void iotjs_binding_initialize(); -void iotjs_binding_finalize(); - +#define JS_DECLARE_PTR(JOBJ, TYPE, NAME) \ + TYPE* NAME = NULL; \ + do { \ + if (!jerry_get_object_native_pointer(JOBJ, (void**)&NAME, \ + &this_module_native_info)) { \ + return JS_CREATE_ERROR(COMMON, "Internal"); \ + } \ + } while (0) + +#define JS_DECLARE_THIS_PTR(type, name) \ + JS_DECLARE_PTR(jthis, iotjs_##type##_t, name) + +#define JS_DECLARE_OBJECT_PTR(index, type, name) \ + JS_DECLARE_PTR(jargv[index], iotjs_##type##_t, name) + +#define JS_GET_REQUIRED_ARG_VALUE(index, target, property, type) \ + do { \ + if (jerry_value_is_undefined(jargv[index])) { \ + return JS_CREATE_ERROR(TYPE, "Missing argument, required " property); \ + } else if (jerry_value_is_##type(jargv[index])) { \ + target = iotjs_jval_as_##type(jargv[index]); \ + } else { \ + return JS_CREATE_ERROR(TYPE, "Bad arguments, required " property \ + " is not a " #type); \ + } \ + } while (0) + +#define JS_GET_REQUIRED_CONF_VALUE(src, target, property, type) \ + do { \ + jerry_value_t value = iotjs_jval_get_property(src, property); \ + if (jerry_value_is_undefined(value)) { \ + jerry_release_value(value); \ + return JS_CREATE_ERROR(TYPE, "Missing argument, required " property); \ + } else if (jerry_value_is_##type(value)) { \ + target = iotjs_jval_as_##type(value); \ + jerry_release_value(value); \ + } else { \ + jerry_release_value(value); \ + return JS_CREATE_ERROR(TYPE, "Bad arguments, required " property \ + " is not a " #type); \ + } \ + } while (0) + +jerry_value_t vm_exec_stop_callback(void* user_p); #endif /* IOTJS_BINDING_H */ diff --git a/src/iotjs_binding_helper.c b/src/iotjs_binding_helper.c index 177099f0d5..b237589c12 100644 --- a/src/iotjs_binding_helper.c +++ b/src/iotjs_binding_helper.c @@ -20,70 +20,78 @@ #include -void iotjs_uncaught_exception(const iotjs_jval_t* jexception) { - const iotjs_jval_t* process = iotjs_module_get(MODULE_PROCESS); +void iotjs_uncaught_exception(jerry_value_t jexception) { + const jerry_value_t process = iotjs_module_get("process"); - iotjs_jval_t jonuncaughtexception = + jerry_value_t jonuncaughtexception = iotjs_jval_get_property(process, IOTJS_MAGIC_STRING__ONUNCAUGHTEXCEPTION); - IOTJS_ASSERT(iotjs_jval_is_function(&jonuncaughtexception)); + IOTJS_ASSERT(jerry_value_is_function(jonuncaughtexception)); - iotjs_jargs_t args = iotjs_jargs_create(1); - iotjs_jargs_append_jval(&args, jexception); + jerry_value_t jres = + jerry_call_function(jonuncaughtexception, process, &jexception, 1); - bool throws; - iotjs_jval_t jres = - iotjs_jhelper_call(&jonuncaughtexception, process, &args, &throws); + jerry_release_value(jonuncaughtexception); - iotjs_jargs_destroy(&args); - iotjs_jval_destroy(&jres); - iotjs_jval_destroy(&jonuncaughtexception); + if (jerry_value_is_error(jres)) { + iotjs_environment_t* env = iotjs_environment_get(); - if (throws) { - exit(2); + if (!iotjs_environment_is_exiting(env)) { + iotjs_set_process_exitcode(2); + iotjs_environment_set_state(env, kExiting); + } } + + jerry_release_value(jres); } void iotjs_process_emit_exit(int code) { - const iotjs_jval_t* process = iotjs_module_get(MODULE_PROCESS); + const jerry_value_t process = iotjs_module_get("process"); - iotjs_jval_t jexit = + jerry_value_t jexit = iotjs_jval_get_property(process, IOTJS_MAGIC_STRING_EMITEXIT); - IOTJS_ASSERT(iotjs_jval_is_function(&jexit)); - - iotjs_jargs_t jargs = iotjs_jargs_create(1); - iotjs_jargs_append_number(&jargs, code); - bool throws; - iotjs_jval_t jres = iotjs_jhelper_call(&jexit, process, &jargs, &throws); + if (jerry_value_is_function(jexit)) { + jerry_value_t jcode = jerry_create_number(code); + jerry_value_t jres = jerry_call_function(jexit, process, &jcode, 1); - iotjs_jargs_destroy(&jargs); - iotjs_jval_destroy(&jres); - iotjs_jval_destroy(&jexit); + if (jerry_value_is_error(jres)) { + iotjs_set_process_exitcode(2); + } - if (throws) { - exit(2); + jerry_release_value(jcode); + jerry_release_value(jres); } + + jerry_release_value(jexit); } // Calls next tick callbacks registered via `process.nextTick()`. -bool iotjs_process_next_tick() { - const iotjs_jval_t* process = iotjs_module_get(MODULE_PROCESS); +bool iotjs_process_next_tick(void) { + iotjs_environment_t* env = iotjs_environment_get(); + + if (iotjs_environment_is_exiting(env)) { + return false; + } - iotjs_jval_t jon_next_tick = + const jerry_value_t process = iotjs_module_get("process"); + + jerry_value_t jon_next_tick = iotjs_jval_get_property(process, IOTJS_MAGIC_STRING__ONNEXTTICK); - IOTJS_ASSERT(iotjs_jval_is_function(&jon_next_tick)); + IOTJS_ASSERT(jerry_value_is_function(jon_next_tick)); + + jerry_value_t jres = + jerry_call_function(jon_next_tick, jerry_create_undefined(), NULL, 0); - iotjs_jval_t jres = - iotjs_jhelper_call_ok(&jon_next_tick, iotjs_jval_get_undefined(), - iotjs_jargs_get_empty()); + bool ret = false; - IOTJS_ASSERT(iotjs_jval_is_boolean(&jres)); + if (!jerry_value_is_error(jres)) { + ret = iotjs_jval_as_boolean(jres); + } - bool ret = iotjs_jval_as_boolean(&jres); - iotjs_jval_destroy(&jres); - iotjs_jval_destroy(&jon_next_tick); + jerry_release_value(jres); + jerry_release_value(jon_next_tick); return ret; } @@ -92,23 +100,29 @@ bool iotjs_process_next_tick() { // Make a callback for the given `function` with `this_` binding and `args` // arguments. The next tick callbacks registered via `process.nextTick()` // will be called after the callback function `function` returns. -void iotjs_make_callback(const iotjs_jval_t* jfunction, - const iotjs_jval_t* jthis, - const iotjs_jargs_t* jargs) { - iotjs_jval_t result = - iotjs_make_callback_with_result(jfunction, jthis, jargs); - iotjs_jval_destroy(&result); +void iotjs_invoke_callback(jerry_value_t jfunc, jerry_value_t jthis, + const jerry_value_t* jargv, size_t jargc) { + jerry_value_t result = + iotjs_invoke_callback_with_result(jfunc, jthis, jargv, jargc); + jerry_release_value(result); } +jerry_value_t iotjs_invoke_callback_with_result(jerry_value_t jfunc, + jerry_value_t jthis, + const jerry_value_t* jargv, + size_t jargc) { + IOTJS_ASSERT(jerry_value_is_function(jfunc)); -iotjs_jval_t iotjs_make_callback_with_result(const iotjs_jval_t* jfunction, - const iotjs_jval_t* jthis, - const iotjs_jargs_t* jargs) { + // If the environment is already exiting just return an undefined value. + if (iotjs_environment_is_exiting(iotjs_environment_get())) { + return jerry_create_undefined(); + } // Calls back the function. - bool throws; - iotjs_jval_t jres = iotjs_jhelper_call(jfunction, jthis, jargs, &throws); - if (throws) { - iotjs_uncaught_exception(&jres); + jerry_value_t jres = jerry_call_function(jfunc, jthis, jargv, jargc); + if (jerry_value_is_error(jres)) { + jerry_value_t errval = jerry_get_value_from_error(jres, false); + iotjs_uncaught_exception(errval); + jerry_release_value(errval); } // Calls the next tick callbacks. @@ -119,6 +133,40 @@ iotjs_jval_t iotjs_make_callback_with_result(const iotjs_jval_t* jfunction, } -const iotjs_jval_t* iotjs_init_process_module() { - return iotjs_module_initialize_if_necessary(MODULE_PROCESS); +int iotjs_process_exitcode(void) { + const jerry_value_t process = iotjs_module_get("process"); + + jerry_value_t jexitcode = + iotjs_jval_get_property(process, IOTJS_MAGIC_STRING_EXITCODE); + uint8_t exitcode = 0; + jerry_value_t num_val = jerry_value_to_number(jexitcode); + if (jerry_value_is_error(num_val)) { + exitcode = 1; + } else { + exitcode = (uint8_t)iotjs_jval_as_number(num_val); + } + + uint8_t native_exitcode = iotjs_environment_get()->exitcode; + if (native_exitcode != exitcode && native_exitcode) { + exitcode = native_exitcode; + } + jerry_release_value(num_val); + jerry_release_value(jexitcode); + return (int)exitcode; +} + + +void iotjs_set_process_exitcode(int code) { + const jerry_value_t process = iotjs_module_get("process"); + jerry_value_t jstring = + jerry_create_string((jerry_char_t*)IOTJS_MAGIC_STRING_EXITCODE); + jerry_value_t jcode = jerry_create_number(code); + jerry_value_t ret_val = jerry_set_property(process, jstring, jcode); + if (jerry_value_is_error(ret_val)) { + iotjs_environment_get()->exitcode = 1; + } + + jerry_release_value(ret_val); + jerry_release_value(jstring); + jerry_release_value(jcode); } diff --git a/src/iotjs_binding_helper.h b/src/iotjs_binding_helper.h index 5ebbaa4d72..727d3f16a3 100644 --- a/src/iotjs_binding_helper.h +++ b/src/iotjs_binding_helper.h @@ -20,21 +20,20 @@ #include "iotjs_binding.h" -void iotjs_uncaught_exception(const iotjs_jval_t* jexception); +void iotjs_uncaught_exception(jerry_value_t jexception); void iotjs_process_emit_exit(int code); -bool iotjs_process_next_tick(); +bool iotjs_process_next_tick(void); -void iotjs_make_callback(const iotjs_jval_t* jfunction, - const iotjs_jval_t* jthis, const iotjs_jargs_t* jargs); - -iotjs_jval_t iotjs_make_callback_with_result(const iotjs_jval_t* jfunction, - const iotjs_jval_t* jthis, - const iotjs_jargs_t* jargs); - - -const iotjs_jval_t* iotjs_init_process_module(); +void iotjs_invoke_callback(jerry_value_t jfunc, jerry_value_t jthis, + const jerry_value_t* jargv, size_t jargc); +jerry_value_t iotjs_invoke_callback_with_result(jerry_value_t jfunc, + jerry_value_t jthis, + const jerry_value_t* jargv, + size_t jargc); +int iotjs_process_exitcode(void); +void iotjs_set_process_exitcode(int code); #endif /* IOTJS_BINDING_HELPER_H */ diff --git a/src/iotjs_compatibility.h b/src/iotjs_compatibility.h new file mode 100644 index 0000000000..b65f8b93e7 --- /dev/null +++ b/src/iotjs_compatibility.h @@ -0,0 +1,43 @@ +/* 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_COMPATIBILITY_H +#define IOTJS_COMPATIBILITY_H + +/* Windows compatiblity defines */ +#ifdef WIN32 +#include +#include +/* Map windows _O_* to O_* defines as on Linux systems. */ +#define O_APPEND _O_APPEND +#define O_CREAT _O_CREAT +#define O_EXCL _O_EXCL +#define O_RDONLY _O_RDONLY +#define O_RDWR _O_RDWR +#define O_TRUNC _O_TRUNC +#define O_WRONLY _O_WRONLY +/* On windows there is no O_SYNC directly, disable it for now. */ +#define O_SYNC 0x0 + +#ifndef PATH_MAX +#define PATH_MAX MAX_PATH +#endif + +#endif + +#ifndef S_ISREG +#define S_ISREG(mode) (((mode) & (S_IFMT)) == S_IFREG) +#endif + +#endif /* IOTJS_COMPATIBILITY_H */ diff --git a/src/iotjs_debuglog.c b/src/iotjs_debuglog.c index f2187fd76e..957401e074 100644 --- a/src/iotjs_debuglog.c +++ b/src/iotjs_debuglog.c @@ -18,14 +18,20 @@ #include "iotjs_debuglog.h" +iotjs_console_out_t iotjs_console_out = NULL; + +void iotjs_set_console_out(iotjs_console_out_t output) { + iotjs_console_out = output; +} + #ifdef ENABLE_DEBUG_LOG int iotjs_debug_level = DBGLEV_ERR; -FILE* iotjs_log_stream; +FILE* iotjs_log_stream = NULL; const char* iotjs_debug_prefix[4] = { "", "ERR", "WRN", "INF" }; #endif // ENABLE_DEBUG_LOG -void init_debug_settings() { +void iotjs_debuglog_init(void) { #ifdef ENABLE_DEBUG_LOG const char* dbglevel = NULL; const char* dbglogfile = NULL; @@ -53,10 +59,10 @@ void init_debug_settings() { #endif // ENABLE_DEBUG_LOG } - -void release_debug_settings() { +void iotjs_debuglog_release(void) { #ifdef ENABLE_DEBUG_LOG - if (iotjs_log_stream != stderr || iotjs_log_stream != stdout) { + if (iotjs_log_stream && iotjs_log_stream != stderr && + iotjs_log_stream != stdout) { fclose(iotjs_log_stream); } // some embed systems(ex, nuttx) may need this diff --git a/src/iotjs_debuglog.h b/src/iotjs_debuglog.h index 74680278ed..6334711639 100644 --- a/src/iotjs_debuglog.h +++ b/src/iotjs_debuglog.h @@ -16,26 +16,46 @@ #ifndef IOTJS_DEBUGLOG_H #define IOTJS_DEBUGLOG_H +#define DBGLEV_ERR 1 +#define DBGLEV_WARN 2 +#define DBGLEV_INFO 3 + +typedef int (*iotjs_console_out_t)(int level, const char* format, ...); +extern iotjs_console_out_t iotjs_console_out; +extern void iotjs_set_console_out(iotjs_console_out_t output); #ifdef ENABLE_DEBUG_LOG -#include extern int iotjs_debug_level; extern FILE* iotjs_log_stream; extern const char* iotjs_debug_prefix[4]; -#define DBGLEV_ERR 1 -#define DBGLEV_WARN 2 -#define DBGLEV_INFO 3 +#if defined(__TIZEN__) +#include +#define DLOG_TAG "IOTJS" +#define DLOG_PRINT(lvl, ...) \ + dlog_print((lvl == DBGLEV_ERR \ + ? DLOG_ERROR \ + : (lvl == DBGLEV_WARN ? DLOG_WARN : DLOG_INFO)), \ + DLOG_TAG, __VA_ARGS__); +#else +#include +#define DLOG_PRINT(lvl, ...) \ + fprintf(iotjs_log_stream, "[%s] ", iotjs_debug_prefix[lvl]); \ + fprintf(iotjs_log_stream, __VA_ARGS__); \ + fprintf(iotjs_log_stream, "\n"); \ + fflush(iotjs_log_stream); +#endif /* defined(__TIZEN__) */ #define IOTJS_DLOG(lvl, ...) \ do { \ if (0 <= lvl && lvl <= iotjs_debug_level && iotjs_log_stream) { \ - fprintf(iotjs_log_stream, "[%s] ", iotjs_debug_prefix[lvl]); \ - fprintf(iotjs_log_stream, __VA_ARGS__); \ - fprintf(iotjs_log_stream, "\n"); \ - fflush(iotjs_log_stream); \ + if (iotjs_console_out) { \ + iotjs_console_out(lvl, __VA_ARGS__); \ + } else { \ + DLOG_PRINT(lvl, __VA_ARGS__) \ + } \ } \ } while (0) #define DLOG(...) IOTJS_DLOG(DBGLEV_ERR, __VA_ARGS__) @@ -58,8 +78,8 @@ extern const char* iotjs_debug_prefix[4]; #endif /* ENABLE_DEBUG_LOG */ -void init_debug_settings(); -void release_debug_settings(); +void iotjs_debuglog_init(void); +void iotjs_debuglog_release(void); #endif /* IOTJS_DEBUGLOG_H */ diff --git a/src/iotjs_def.h b/src/iotjs_def.h index 5d2788fa9f..06e5a0ea6a 100644 --- a/src/iotjs_def.h +++ b/src/iotjs_def.h @@ -22,21 +22,30 @@ #if defined(__NUTTX__) || defined(__TIZENRT__) #define IOTJS_MAX_READ_BUFFER_SIZE 1023 #define IOTJS_MAX_PATH_SIZE 120 -#else +#else /* !__NUTTX__ && !__TIZENRT__ */ #define IOTJS_MAX_READ_BUFFER_SIZE 65535 #define IOTJS_MAX_PATH_SIZE PATH_MAX -#endif -#endif +#endif /* __NUTTX__ || TIZENRT */ +#endif /* IOTJS_MAX_READ_BUFFER_SIZE */ #ifndef IOTJS_ASSERT #ifdef NDEBUG #define IOTJS_ASSERT(x) ((void)(x)) -#else -#define IOTJS_ASSERT(x) assert(x) -#endif -#endif - +#else /* !NDEBUG */ +extern void print_stacktrace(void); +extern void force_terminate(void); +#define IOTJS_ASSERT(x) \ + do { \ + if (!(x)) { \ + fprintf(stderr, "%s:%d: Assertion '%s' failed.\n", __FILE__, __LINE__, \ + #x); \ + print_stacktrace(); \ + force_terminate(); \ + } \ + } while (0) +#endif /* NDEBUG */ +#endif /* IOTJS_ASSERT */ #if defined(__arm__) #define TARGET_ARCH "arm" @@ -44,112 +53,56 @@ #define TARGET_ARCH "ia32" #elif defined(__x86_64__) #define TARGET_ARCH "x64" -#else +#else /* !__arm__ && !__i686__ && !__x86_64__ */ #define TARGET_ARCH "unknown" -#endif +#endif /* __arm__ */ #if defined(__linux__) +#if defined(__TIZEN__) +#define TARGET_OS "tizen" +#else #define TARGET_OS "linux" +#endif /* __TIZEN__ */ #elif defined(__NUTTX__) #define TARGET_OS "nuttx" #elif defined(__APPLE__) #define TARGET_OS "darwin" #elif defined(__TIZENRT__) #define TARGET_OS "tizenrt" -#else +#elif defined(WIN32) +#define TARGET_OS "windows" +#else /* !__linux__ && !__NUTTX__ !__APPLE__ && !__TIZENRT__ && !WIN32 */ #define TARGET_OS "unknown" -#endif +#endif /* __linux__ */ + +#define IOTJS_VERSION "1.0.0" #if !defined(STRINGIFY) #define STRINGIFY(x) #x -#endif +#endif /* STRINGIFY */ #if !defined(TOSTRING) #define TOSTRING(x) STRINGIFY(x) -#endif - +#endif /* TOSTRING */ #if !defined(TARGET_BOARD) #define TARGET_BOARD "unknown" -#endif - +#endif /* TARGET_BOARD */ -#define IOTJS_VALID_MAGIC_SEQUENCE 0xfee1c001 /* feel cool */ -#define IOTJS_INVALID_MAGIC_SEQUENCE 0xfee1badd /* feel bad */ - -#define IOTJS_DECLARE_THIS(iotjs_classname_t, x) \ - iotjs_classname_t##_impl_t* _this = &(x)->unsafe; +#define NODE_MAJOR_VERSION 1 +#define NODE_MINOR_VERSION 0 +#define NODE_PATCH_VERSION 0 /* Avoid compiler warnings if needed. */ #define IOTJS_UNUSED(x) ((void)(x)) - -#ifdef NDEBUG - -#define IOTJS_VALIDATED_STRUCT(iotjs_classname_t) \ - iotjs_classname_t##_impl_t; \ - typedef struct iotjs_classname_t { \ - iotjs_classname_t##_impl_t unsafe; \ - } iotjs_classname_t; - -#define IOTJS_VALIDATED_STRUCT_STATIC_INITIALIZER(...) __VA_ARGS__ - -#define IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_classname_t, x) \ - IOTJS_DECLARE_THIS(iotjs_classname_t, x); -#define IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_classname_t, x) \ - IOTJS_DECLARE_THIS(iotjs_classname_t, x); -#define IOTJS_VALIDATED_STRUCT_METHOD(iotjs_classname_t, x) \ - IOTJS_DECLARE_THIS(iotjs_classname_t, x); - -#define IOTJS_VALIDATABLE_STRUCT_DESTRUCTOR_VALIDATE(iotjs_classname_t, x) -#define IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_classname_t, x) - -#else /* !NDEBUG */ - -#define IOTJS_VALIDATED_STRUCT(iotjs_classname_t) \ - iotjs_classname_t##_impl_t; \ - typedef struct iotjs_classname_t { \ - iotjs_classname_t##_impl_t unsafe; \ - uint32_t flag_create; \ - char* valgrind_tracer; \ - } iotjs_classname_t; - -#define IOTJS_VALIDATED_STRUCT_STATIC_INITIALIZER(...) \ - { IOTJS_VALID_MAGIC_SEQUENCE, iotjs_buffer_allocate(4), __VA_ARGS__ } - -#define IOTJS_VALIDATE_FLAG(iotjs_classname_t, x) \ - if ((x)->flag_create != IOTJS_VALID_MAGIC_SEQUENCE) { \ - DLOG("`%s %s` is not initialized properly.", #iotjs_classname_t, #x); \ - IOTJS_ASSERT(false); \ +#define IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(name) \ + static void iotjs_##name##_destroy(iotjs_##name##_t* wrap); \ + static const jerry_object_native_info_t this_module_native_info = { \ + .free_cb = (jerry_object_native_free_callback_t)iotjs_##name##_destroy \ } -#define IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_classname_t, x) \ - IOTJS_DECLARE_THIS(iotjs_classname_t, x); \ - /* IOTJS_ASSERT((x)->flag_create != IOTJS_VALID_MAGIC_SEQUENCE); */ \ - (x)->flag_create = IOTJS_VALID_MAGIC_SEQUENCE; \ - (x)->valgrind_tracer = iotjs_buffer_allocate(4); - -#define IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_classname_t, x) \ - IOTJS_DECLARE_THIS(iotjs_classname_t, x); \ - IOTJS_VALIDATE_FLAG(iotjs_classname_t, x); \ - (x)->flag_create = IOTJS_INVALID_MAGIC_SEQUENCE; \ - iotjs_buffer_release((x)->valgrind_tracer); - -#define IOTJS_VALIDATED_STRUCT_METHOD(iotjs_classname_t, x) \ - IOTJS_DECLARE_THIS(iotjs_classname_t, x); \ - IOTJS_VALIDATE_FLAG(iotjs_classname_t, x); - -#define IOTJS_VALIDATABLE_STRUCT_DESTRUCTOR_VALIDATE(iotjs_classname_t, x) \ - IOTJS_VALIDATE_FLAG(iotjs_classname_t, x); \ - (x)->flag_create = IOTJS_INVALID_MAGIC_SEQUENCE; \ - iotjs_buffer_release((x)->valgrind_tracer); - -#define IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_classname_t, x) \ - IOTJS_VALIDATE_FLAG(iotjs_classname_t, x); - -#endif /* NDEBUG */ - #include #include #include /* PATH_MAX */ diff --git a/src/iotjs_env.c b/src/iotjs_env.c index e5299c5cb6..09ff684729 100644 --- a/src/iotjs_env.c +++ b/src/iotjs_env.c @@ -17,30 +17,46 @@ #include "iotjs_def.h" #include "iotjs_env.h" +#include #include +typedef enum { + OPT_HELP, + OPT_MEM_STATS, + OPT_SHOW_OP, +#ifdef JERRY_DEBUGGER + OPT_DEBUG_SERVER, + OPT_DEBUGGER_WAIT_SOURCE, + OPT_DEBUG_PORT, + OPT_DEBUG_CHANNEL, + OPT_DEBUG_PROTOCOL, + OPT_DEBUG_SERIAL_CONFIG, +#endif + NUM_OF_OPTIONS +} cli_option_id_t; + +typedef struct { + const cli_option_id_t id; + const char* opt; + const char* longopt; + const char* help; + const uint32_t more; // The number of options coming with the given option +} cli_option_t; + +#define CLI_DEFAULT_HELP_STRING \ + "Usage: iotjs [options] {FILE | FILE.js} [arguments]\n" static iotjs_environment_t current_env; static bool initialized = false; - -/** - * Constructor/Destructor on private section. - * To prevent create an instance of iotjs_environment_t. - * The only way to get an instance of environment is iotjs_environment_get() - */ - - -static void iotjs_environment_initialize(iotjs_environment_t* env); -static void iotjs_environment_destroy(iotjs_environment_t* env); - +static void initialize(iotjs_environment_t* env); /** * Get the singleton instance of iotjs_environment_t. */ -const iotjs_environment_t* iotjs_environment_get() { +iotjs_environment_t* iotjs_environment_get(void) { if (!initialized) { - iotjs_environment_initialize(¤t_env); + initialize(¤t_env); initialized = true; } return ¤t_env; @@ -48,45 +64,32 @@ const iotjs_environment_t* iotjs_environment_get() { /** - * Release the singleton instance of iotjs_environment_t. - */ -void iotjs_environment_release() { - if (initialized) { - iotjs_environment_destroy(¤t_env); - initialized = false; - } -} - - -/** - * Initialize an instance of iotjs_environment_t. + * Release the singleton instance of iotjs_environment_t, and debugger config. */ -static void iotjs_environment_initialize(iotjs_environment_t* env) { - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_environment_t, env); - - _this->argc = 0; - _this->argv = NULL; - _this->loop = NULL; - _this->state = kInitializing; - _this->config.memstat = false; - _this->config.show_opcode = false; +void iotjs_environment_release(void) { + if (!initialized) + return; + + iotjs_environment_t* env = iotjs_environment_get(); +#ifdef JERRY_DEBUGGER + IOTJS_RELEASE(env->config.debugger); +#endif + IOTJS_RELEASE(env->argv); + initialized = false; } -/** - * Destroy an instance of iotjs_environment_t. - */ -static void iotjs_environment_destroy(iotjs_environment_t* env) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_environment_t, env); - if (_this->argv) { - // release command line argument strings. - // _argv[0] and _argv[1] refer addresses in static memory space. - // Others refer addresses in heap space that is need to be deallocated. - for (uint32_t i = 2; i < _this->argc; ++i) { - iotjs_buffer_release(_this->argv[i]); - } - iotjs_buffer_release((char*)_this->argv); - } +static void initialize(iotjs_environment_t* env) { + env->argc = 0; + env->argv = NULL; + env->loop = NULL; + env->state = kInitializing; + env->config.memstat = false; + env->config.show_opcode = false; +#ifdef JERRY_DEBUGGER + env->config.debugger = NULL; +#endif + env->exitcode = 0; } @@ -96,96 +99,261 @@ static void iotjs_environment_destroy(iotjs_environment_t* env) { bool iotjs_environment_parse_command_line_arguments(iotjs_environment_t* env, uint32_t argc, char** argv) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_environment_t, env); - - // Parse IoT.js command line arguments. + // declare options + const cli_option_t opts[] = { + { + .id = OPT_HELP, + .opt = "h", + .longopt = "help", + .help = "print this help and exit", + }, + { + .id = OPT_MEM_STATS, + .longopt = "mem-stats", + .help = "dump memory statistics", + }, + { + .id = OPT_SHOW_OP, + .longopt = "show-opcodes", + .help = "dump parser byte-code", + }, +#ifdef JERRY_DEBUGGER + { + .id = OPT_DEBUG_SERVER, + .opt = "d", + .longopt = "start-debug-server", + .help = "start debug server and wait for a connecting client", + }, + { + .id = OPT_DEBUGGER_WAIT_SOURCE, + .opt = "w", + .longopt = "debugger-wait-source", + .help = "wait for an executable source from the client", + }, + { + .id = OPT_DEBUG_PORT, + .longopt = "debug-port", + .more = 1, + .help = "debug server port (default: 5001)", + }, + { + .id = OPT_DEBUG_CHANNEL, + .longopt = "debug-channel", + .help = "specify the debugger transmission channel" + " (default: websocket)", + }, + { + .id = OPT_DEBUG_PROTOCOL, + .longopt = "debug-protocol", + .help = "Specify the transmission protocol over the communication" + " channel (default: tcp)", + }, + { + .id = OPT_DEBUG_SERIAL_CONFIG, + .longopt = "debug-serial-config", + .help = "configure parameters for serial port" + " (default: /dev/ttyS0,115200,8,N,1)", + }, +#endif + }; + + const cli_option_t* cur_opt; uint32_t i = 1; + while (i < argc && argv[i][0] == '-') { - if (!strcmp(argv[i], "--memstat")) { - _this->config.memstat = true; - } else if (!strcmp(argv[i], "--show-opcodes")) { - _this->config.show_opcode = true; - } else if (!strcmp(argv[i], "--start-debug-server")) { - _this->config.debugger = true; - } else { + cur_opt = NULL; + + // check if the known option is given. + for (uint32_t k = 0; k < NUM_OF_OPTIONS; k++) { + if ((opts[k].opt && !strcmp(&argv[i][1], opts[k].opt)) || + (opts[k].longopt && !strcmp(&argv[i][2], opts[k].longopt))) { + cur_opt = &opts[k]; + break; + } + } + + if (cur_opt == NULL) { fprintf(stderr, "unknown command line option: %s\n", argv[i]); return false; } - ++i; + + switch (cur_opt->id) { + case OPT_HELP: { + fprintf(stderr, "%s\n Options:\n\n", CLI_DEFAULT_HELP_STRING); + for (uint32_t k = 0; k < NUM_OF_OPTIONS; k++) { + if (opts[k].opt) { + fprintf(stderr, " -%s, --%-21s %s\n", opts[k].opt, + opts[k].longopt, opts[k].help); + } else { + fprintf(stderr, " --%-25s %s\n", opts[k].longopt, opts[k].help); + } + } + fprintf(stderr, "\n"); + return false; + } + case OPT_MEM_STATS: { + env->config.memstat = true; + } break; + case OPT_SHOW_OP: { + env->config.show_opcode = true; + } break; +#ifdef JERRY_DEBUGGER + case OPT_DEBUGGER_WAIT_SOURCE: + case OPT_DEBUG_SERVER: { + if (!env->config.debugger) { + env->config.debugger = + (DebuggerConfig*)iotjs_buffer_allocate(sizeof(DebuggerConfig)); + } + env->config.debugger->port = 5001; + env->config.debugger->context_reset = false; + env->config.debugger->wait_source = + cur_opt->id == OPT_DEBUGGER_WAIT_SOURCE; + char default_channel[] = "websocket"; + char default_protocol[] = "tcp"; + char default_serial_config[] = "/dev/ttyS0,115200,8,N,1"; + memcpy(env->config.debugger->channel, default_channel, + strlen(default_channel) + 1); + memcpy(env->config.debugger->protocol, default_protocol, + strlen(default_protocol) + 1); + memcpy(env->config.debugger->serial_config, default_serial_config, + strlen(default_serial_config) + 1); + } break; + case OPT_DEBUG_PORT: { + if (env->config.debugger) { + char* pos = NULL; + env->config.debugger->port = (uint16_t)strtoul(argv[i + 1], &pos, 10); + } + i++; + } break; + case OPT_DEBUG_CHANNEL: { + if (env->config.debugger) { + memset(env->config.debugger->channel, 0, + strlen(env->config.debugger->channel) + 1); + memcpy(env->config.debugger->channel, argv[i + 1], + strlen(argv[i + 1]) + 1); + + if (strcmp(env->config.debugger->channel, "websocket") && + strcmp(env->config.debugger->channel, "rawpacket")) { + fprintf(stderr, + "Debug channel %s is not supported." + " Only websocket or rawpacket is allowed\n", + env->config.debugger->channel); + return false; + } + } + i++; + } break; + case OPT_DEBUG_PROTOCOL: { + if (env->config.debugger) { + memset(env->config.debugger->protocol, 0, + strlen(env->config.debugger->protocol) + 1); + memcpy(env->config.debugger->protocol, argv[i + 1], + strlen(argv[i + 1]) + 1); + + if (strcmp(env->config.debugger->protocol, "tcp") && + strcmp(env->config.debugger->protocol, "serial")) { + fprintf(stderr, + "Debug protocol %s is not supported." + " Only tcp or serial is allowed\n", + env->config.debugger->protocol); + return false; + } + } + i++; + } break; + case OPT_DEBUG_SERIAL_CONFIG: { + if (env->config.debugger) { + memset(env->config.debugger->serial_config, 0, + strlen(env->config.debugger->serial_config) + 1); + memcpy(env->config.debugger->serial_config, argv[i + 1], + strlen(argv[i + 1]) + 1); + } + i++; + } break; +#endif + default: + break; + } + + // increase index of argv + i += (1 + cur_opt->more); } - // There must be at least one argument after processing the IoT.js args. - if ((argc - i) < 1) { - fprintf(stderr, - "Usage: iotjs [options] {script | script.js} [arguments]\n"); +#ifdef JERRY_DEBUGGER + // If IoT.js is waiting for source from the debugger client, + // Further processing over command line argument is not needed. + if (env->config.debugger && env->config.debugger->wait_source) + return true; +#endif + + // There must be at least one argument after processing the IoT.js args, + if (argc - i < 1) { + fprintf(stderr, CLI_DEFAULT_HELP_STRING); return false; } // Remaining arguments are for application. - _this->argc = 2; - size_t buffer_size = ((size_t)(_this->argc + argc - i)) * sizeof(char*); - _this->argv = (char**)iotjs_buffer_allocate(buffer_size); - _this->argv[0] = argv[0]; - _this->argv[1] = argv[i++]; - while (i < argc) { - _this->argv[_this->argc] = iotjs_buffer_allocate(strlen(argv[i]) + 1); - strcpy(_this->argv[_this->argc], argv[i]); - _this->argc++; - i++; - } + env->argc = 2; + size_t buffer_size = ((size_t)(env->argc + argc - i)) * sizeof(char*); + env->argv = (char**)iotjs_buffer_allocate(buffer_size); + env->argv[0] = argv[0]; + env->argv[1] = argv[i++]; + + // Clonning for argv is not required. + // 1) We will only read + // 2) Standard C guarantees that strings pointed by the argv array shall + // retain between program startup and program termination + while (i < argc) + env->argv[env->argc++] = argv[i++]; return true; } uint32_t iotjs_environment_argc(const iotjs_environment_t* env) { - const IOTJS_VALIDATED_STRUCT_METHOD(iotjs_environment_t, env); - return _this->argc; + return env->argc; } const char* iotjs_environment_argv(const iotjs_environment_t* env, uint32_t idx) { - const IOTJS_VALIDATED_STRUCT_METHOD(iotjs_environment_t, env); - return _this->argv[idx]; + return env->argv[idx]; } uv_loop_t* iotjs_environment_loop(const iotjs_environment_t* env) { - const IOTJS_VALIDATED_STRUCT_METHOD(iotjs_environment_t, env); - return _this->loop; + return env->loop; } void iotjs_environment_set_loop(iotjs_environment_t* env, uv_loop_t* loop) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_environment_t, env); - _this->loop = loop; + env->loop = loop; } const Config* iotjs_environment_config(const iotjs_environment_t* env) { - const IOTJS_VALIDATED_STRUCT_METHOD(iotjs_environment_t, env); - return &_this->config; -} - - -void iotjs_environment_go_state_running_main(iotjs_environment_t* env) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_environment_t, env); - - IOTJS_ASSERT(_this->state == kInitializing); - _this->state = kRunningMain; + return &env->config; } -void iotjs_environment_go_state_running_loop(iotjs_environment_t* env) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_environment_t, env); - - IOTJS_ASSERT(_this->state == kRunningMain); - _this->state = kRunningLoop; +void iotjs_environment_set_state(iotjs_environment_t* env, State s) { + switch (s) { + case kInitializing: + break; + case kRunningMain: + IOTJS_ASSERT(env->state == kInitializing); + break; + case kRunningLoop: + IOTJS_ASSERT(env->state == kRunningMain); + break; + case kExiting: + IOTJS_ASSERT(env->state < kExiting); + break; + default: + IOTJS_ASSERT(!"Should not reach here."); + } + env->state = s; } - -void iotjs_environment_go_state_exiting(iotjs_environment_t* env) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_environment_t, env); - IOTJS_ASSERT(_this->state < kExiting); - _this->state = kExiting; +bool iotjs_environment_is_exiting(iotjs_environment_t* env) { + return env->state == kExiting; } diff --git a/src/iotjs_env.h b/src/iotjs_env.h index 31b04da0c1..ffd8450f5a 100644 --- a/src/iotjs_env.h +++ b/src/iotjs_env.h @@ -18,11 +18,23 @@ #include "uv.h" +#ifdef JERRY_DEBUGGER +typedef struct { + bool wait_source; + bool context_reset; + uint16_t port; + char channel[16]; + char protocol[16]; + char serial_config[64]; +} DebuggerConfig; +#endif typedef struct { - bool memstat; - bool show_opcode; - bool debugger; + uint32_t memstat : 1; + uint32_t show_opcode : 1; +#ifdef JERRY_DEBUGGER + DebuggerConfig* debugger; +#endif } Config; typedef enum { @@ -48,11 +60,14 @@ typedef struct { // Run config Config config; -} IOTJS_VALIDATED_STRUCT(iotjs_environment_t); + + // Exitcode + uint8_t exitcode; +} iotjs_environment_t; -const iotjs_environment_t* iotjs_environment_get(); -void iotjs_environment_release(); +iotjs_environment_t* iotjs_environment_get(void); +void iotjs_environment_release(void); bool iotjs_environment_parse_command_line_arguments(iotjs_environment_t* env, uint32_t argc, char** argv); @@ -65,10 +80,11 @@ uv_loop_t* iotjs_environment_loop(const iotjs_environment_t* env); void iotjs_environment_set_loop(iotjs_environment_t* env, uv_loop_t* loop); const Config* iotjs_environment_config(const iotjs_environment_t* env); +#ifdef JERRY_DEBUGGER +const DebuggerConfig* iotjs_environment_dconfig(const iotjs_environment_t* env); +#endif -void iotjs_environment_go_state_running_main(iotjs_environment_t* env); -void iotjs_environment_go_state_running_loop(iotjs_environment_t* env); -void iotjs_environment_go_state_exiting(iotjs_environment_t* env); - +void iotjs_environment_set_state(iotjs_environment_t* env, State s); +bool iotjs_environment_is_exiting(iotjs_environment_t* env); #endif /* IOTJS_ENV_H */ diff --git a/src/iotjs_handlewrap.c b/src/iotjs_handlewrap.c deleted file mode 100644 index fb03a3de36..0000000000 --- a/src/iotjs_handlewrap.c +++ /dev/null @@ -1,125 +0,0 @@ -/* Copyright 2015-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_def.h" -#include "iotjs_handlewrap.h" - - -void iotjs_handlewrap_initialize(iotjs_handlewrap_t* handlewrap, - const iotjs_jval_t* jobject, - uv_handle_t* handle, - JNativeInfoType native_info) { - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_handlewrap_t, handlewrap); - - // Increase ref count of Javascript object to guarantee it is alive until the - // handle has closed. - iotjs_jval_t jobjectref = iotjs_jval_create_copied(jobject); - iotjs_jobjectwrap_initialize(&_this->jobjectwrap, &jobjectref, native_info); - - _this->handle = handle; - _this->on_close_cb = NULL; - - handle->data = handlewrap; - - iotjs_handlewrap_validate(handlewrap); -} - - -void iotjs_handlewrap_destroy(iotjs_handlewrap_t* handlewrap) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_handlewrap_t, handlewrap); - - // Handle should have been release before this. - IOTJS_ASSERT(_this->handle == NULL); - - iotjs_jobjectwrap_destroy(&_this->jobjectwrap); -} - - -iotjs_handlewrap_t* iotjs_handlewrap_from_handle(uv_handle_t* handle) { - iotjs_handlewrap_t* handlewrap = (iotjs_handlewrap_t*)(handle->data); - iotjs_handlewrap_validate(handlewrap); - return handlewrap; -} - - -iotjs_handlewrap_t* iotjs_handlewrap_from_jobject(const iotjs_jval_t* jobject) { - iotjs_handlewrap_t* handlewrap = - (iotjs_handlewrap_t*)(iotjs_jval_get_object_native_handle(jobject)); - iotjs_handlewrap_validate(handlewrap); - return handlewrap; -} - - -uv_handle_t* iotjs_handlewrap_get_uv_handle(iotjs_handlewrap_t* handlewrap) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_handlewrap_t, handlewrap); - iotjs_handlewrap_validate(handlewrap); - return _this->handle; -} - - -iotjs_jval_t* iotjs_handlewrap_jobject(iotjs_handlewrap_t* handlewrap) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_handlewrap_t, handlewrap); - iotjs_handlewrap_validate(handlewrap); - return iotjs_jobjectwrap_jobject(&_this->jobjectwrap); -} - - -static void iotjs_handlewrap_on_close(iotjs_handlewrap_t* handlewrap) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_handlewrap_t, handlewrap); - - // The handle closed. - // Calls registered close handler function. - if (_this->on_close_cb) { - _this->on_close_cb(_this->handle); - } - - // Set handle null. - _this->handle = NULL; - - // Decrease ref count of Javascript object. From now the object can be - // reclaimed. - iotjs_jval_destroy(iotjs_jobjectwrap_jobject(&_this->jobjectwrap)); -} - - -static void iotjs_on_handle_closed(uv_handle_t* handle) { - iotjs_handlewrap_t* handlewrap = iotjs_handlewrap_from_handle(handle); - iotjs_handlewrap_on_close(handlewrap); -} - - -void iotjs_handlewrap_close(iotjs_handlewrap_t* handlewrap, - OnCloseHandler on_close_cb) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_handlewrap_t, handlewrap); - - if (_this->handle != NULL && !uv_is_closing(_this->handle)) { - _this->on_close_cb = on_close_cb; - uv_close(_this->handle, iotjs_on_handle_closed); - } else { - DDLOG("Attempt to close uninitialized or already closed handle"); - } -} - - -void iotjs_handlewrap_validate(iotjs_handlewrap_t* handlewrap) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_handlewrap_t, handlewrap); - - IOTJS_ASSERT((iotjs_handlewrap_t*)_this == handlewrap); - IOTJS_ASSERT((iotjs_jobjectwrap_t*)_this == &_this->jobjectwrap); - IOTJS_ASSERT((void*)_this == _this->handle->data); - IOTJS_ASSERT((uintptr_t)_this == - iotjs_jval_get_object_native_handle( - iotjs_jobjectwrap_jobject(&_this->jobjectwrap))); -} diff --git a/src/iotjs_handlewrap.h b/src/iotjs_handlewrap.h deleted file mode 100644 index ed614c6171..0000000000 --- a/src/iotjs_handlewrap.h +++ /dev/null @@ -1,72 +0,0 @@ -/* Copyright 2015-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_HANDLEWRAP_H -#define IOTJS_HANDLEWRAP_H - - -#include - -#include "iotjs_binding.h" -#include "iotjs_objectwrap.h" - - -typedef void (*OnCloseHandler)(uv_handle_t*); - - -// UV handle wrapper. -// This wrapper connects a Javascript object and a libuv handler. -// This wrapper will increase ref count for the Javascript object and decrease -// it after corresponding handle has closed. Hence the Javascript object will -// not turn into garbage until the handle is open. - -// Javascript object -// -> -// Create a handle wrap, initializing uv handle, increase ref count. -// -> -// The javascript object will be alive until handle has closed. -// -> -// Handle closed, release handle, decrease ref count. -// -> -// The javascript object now can be reclaimed by GC. - -typedef struct { - iotjs_jobjectwrap_t jobjectwrap; - uv_handle_t* handle; - OnCloseHandler on_close_cb; -} IOTJS_VALIDATED_STRUCT(iotjs_handlewrap_t); - - -// jobject: Object that connect with the uv handle -void iotjs_handlewrap_initialize(iotjs_handlewrap_t* handlewrap, - const iotjs_jval_t* jobject, - uv_handle_t* handle, - JNativeInfoType native_info); - -void iotjs_handlewrap_destroy(iotjs_handlewrap_t* handlewrap); - -void iotjs_handlewrap_close(iotjs_handlewrap_t* handlewrap, - OnCloseHandler on_close_cb); - -iotjs_handlewrap_t* iotjs_handlewrap_from_handle(uv_handle_t* handle); -iotjs_handlewrap_t* iotjs_handlewrap_from_jobject(const iotjs_jval_t* jobject); - -uv_handle_t* iotjs_handlewrap_get_uv_handle(iotjs_handlewrap_t* handlewrap); -iotjs_jval_t* iotjs_handlewrap_jobject(iotjs_handlewrap_t* handlewrap); - -void iotjs_handlewrap_validate(iotjs_handlewrap_t* handlewrap); - - -#endif /* IOTJS_HANDLEWRAP_H */ diff --git a/src/iotjs_magic_strings.h b/src/iotjs_magic_strings.h index c35709e5e9..bc94d43a29 100644 --- a/src/iotjs_magic_strings.h +++ b/src/iotjs_magic_strings.h @@ -13,174 +13,427 @@ * limitations under the License. */ -#ifndef IOTJS_STRING_CONSTANTS_H -#define IOTJS_STRING_CONSTANTS_H +#ifndef IOTJS_MAGIC_STRINGS_H +#define IOTJS_MAGIC_STRINGS_H +#if ENABLE_MODULE_SPI #define IOTJS_MAGIC_STRING_0 "0" #define IOTJS_MAGIC_STRING_1 "1" #define IOTJS_MAGIC_STRING_2 "2" #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 +#define IOTJS_MAGIC_STRING_ADDHEADER "addHeader" +#if ENABLE_MODULE_UDP #define IOTJS_MAGIC_STRING_ADDMEMBERSHIP "addMembership" +#endif #define IOTJS_MAGIC_STRING_ADDRESS "address" #define IOTJS_MAGIC_STRING_ARCH "arch" #define IOTJS_MAGIC_STRING_ARGV "argv" +#define IOTJS_MAGIC_STRING_BASE64 "base64" +#if ENABLE_MODULE_CRYPTO +#define IOTJS_MAGIC_STRING_BASE64ENCODE "base64Encode" +#endif +#if ENABLE_MODULE_UART #define IOTJS_MAGIC_STRING_BAUDRATE "baudRate" +#endif #define IOTJS_MAGIC_STRING_BIND "bind" +#if ENABLE_MODULE_BLE #define IOTJS_MAGIC_STRING_BINDCONTROL "bindControl" +#endif #define IOTJS_MAGIC_STRING_BINDING "binding" +#if ENABLE_MODULE_BLE #define IOTJS_MAGIC_STRING_BINDRAW "bindRaw" #define IOTJS_MAGIC_STRING_BINDUSER "bindUser" +#endif +#if ENABLE_MODULE_SPI #define IOTJS_MAGIC_STRING_BITORDER "bitOrder" #define IOTJS_MAGIC_STRING_BITORDER_U "BITORDER" #define IOTJS_MAGIC_STRING_BITSPERWORD "bitsPerWord" +#endif #define IOTJS_MAGIC_STRING_BOARD "board" +#if ENABLE_MODULE_GPIO #define IOTJS_MAGIC_STRING_BOTH_U "BOTH" +#endif #define IOTJS_MAGIC_STRING_BUFFER "Buffer" -#define IOTJS_MAGIC_STRING__BUFFER "_buffer" -#define IOTJS_MAGIC_STRING__BUILTIN "_builtin" +#define IOTJS_MAGIC_STRING_BUILTIN_MODULES "builtin_modules" +#if ENABLE_MODULE_I2C || ENABLE_MODULE_SPI +#define IOTJS_MAGIC_STRING_BUS "bus" +#endif #define IOTJS_MAGIC_STRING_BYTELENGTH "byteLength" #define IOTJS_MAGIC_STRING_BYTEPARSED "byteParsed" +#define IOTJS_MAGIC_STRING_FROM_ARRAYBUFFER "fromArrayBuffer" +#if ENABLE_MODULE_HTTPS || ENABLE_MODULE_TLS +#define IOTJS_MAGIC_STRING_CA "ca" +#define IOTJS_MAGIC_STRING_CERT "cert" +#endif #define IOTJS_MAGIC_STRING_CHDIR "chdir" +#if ENABLE_MODULE_PWM #define IOTJS_MAGIC_STRING_CHIP "chip" +#endif +#if ENABLE_MODULE_SPI #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_COMPARE "compare" #define IOTJS_MAGIC_STRING_COMPILE "compile" -#define IOTJS_MAGIC_STRING_COMPILENATIVEPTR "compileNativePtr" +#define IOTJS_MAGIC_STRING_COMPILEMODULE "compileModule" +#define IOTJS_MAGIC_STRING_CONFIG "config" #define IOTJS_MAGIC_STRING_CONNECT "connect" #define IOTJS_MAGIC_STRING_COPY "copy" +#if ENABLE_MODULE_HTTPS +#define IOTJS_MAGIC_STRING_CREATEREQUEST "createRequest" +#endif #define IOTJS_MAGIC_STRING__CREATESTAT "_createStat" #define IOTJS_MAGIC_STRING_CREATETCP "createTCP" #define IOTJS_MAGIC_STRING_CWD "cwd" +#define IOTJS_MAGIC_STRING_DATA "data" +#if ENABLE_MODULE_UART #define IOTJS_MAGIC_STRING_DATABITS "dataBits" +#endif +#ifdef DEBUG +#define IOTJS_MAGIC_STRING_DEBUG "debug" +#endif +#define IOTJS_MAGIC_STRING_DEBUGGERGETSOURCE "debuggerGetSource" +#define IOTJS_MAGIC_STRING_DEBUGGERWAITSOURCE "debuggerWaitSource" +#if ENABLE_MODULE_WEBSOCKET +#define IOTJS_MAGIC_STRING_DECODEFRAME "decodeFrame" +#endif #define IOTJS_MAGIC_STRING_DEVICE "device" +#if ENABLE_MODULE_GPIO #define IOTJS_MAGIC_STRING_DIRECTION "direction" #define IOTJS_MAGIC_STRING_DIRECTION_U "DIRECTION" +#endif +#if 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" +#endif +#if ENABLE_MODULE_PWM #define IOTJS_MAGIC_STRING_DUTYCYCLE "dutyCycle" +#endif +#if ENABLE_MODULE_GPIO #define IOTJS_MAGIC_STRING_EDGE "edge" #define IOTJS_MAGIC_STRING_EDGE_U "EDGE" +#endif #define IOTJS_MAGIC_STRING_EMIT "emit" #define IOTJS_MAGIC_STRING_EMITEXIT "emitExit" +#if ENABLE_MODULE_TLS +#define IOTJS_MAGIC_STRING_END "end" +#endif #define IOTJS_MAGIC_STRING_ENV "env" #define IOTJS_MAGIC_STRING_ERRNAME "errname" #define IOTJS_MAGIC_STRING_EXECUTE "execute" +#define IOTJS_MAGIC_STRING_EXITCODE "exitCode" #define IOTJS_MAGIC_STRING_EXPORT "export" +#if ENABLE_MODULE_GPIO #define IOTJS_MAGIC_STRING_FALLING_U "FALLING" +#endif #define IOTJS_MAGIC_STRING_FAMILY "family" #define IOTJS_MAGIC_STRING_FINISH "finish" -#define IOTJS_MAGIC_STRING_FLOAT "FLOAT" +#if ENABLE_MODULE_HTTPS +#define IOTJS_MAGIC_STRING_FINISHREQUEST "finishRequest" +#endif +#if ENABLE_MODULE_GPIO +#define IOTJS_MAGIC_STRING_FLOAT_U "FLOAT" +#endif #define IOTJS_MAGIC_STRING_FSTAT "fstat" +#if EXPOSE_GC +#define IOTJS_MAGIC_STRING_GC "gc" +#endif #define IOTJS_MAGIC_STRING_GETADDRINFO "getaddrinfo" #define IOTJS_MAGIC_STRING_GETSOCKNAME "getsockname" +#if ENABLE_MODULE_GPIO #define IOTJS_MAGIC_STRING_GPIO "Gpio" +#endif #define IOTJS_MAGIC_STRING_HANDLER "handler" #define IOTJS_MAGIC_STRING_HANDLETIMEOUT "handleTimeout" #define IOTJS_MAGIC_STRING_HEADERS "headers" -#define IOTJS_MAGIC_STRING_HEXWRITE "hexWrite" -#define IOTJS_MAGIC_STRING_HIGH "HIGH" -#define IOTJS_MAGIC_STRING_HOME "HOME" +#define IOTJS_MAGIC_STRING_HEX "hex" +#if ENABLE_MODULE_SPI +#define IOTJS_MAGIC_STRING_HIGH_U "HIGH" +#endif +#define IOTJS_MAGIC_STRING_HOME_U "HOME" +#define IOTJS_MAGIC_STRING_HOST "host" #define IOTJS_MAGIC_STRING_HTTPPARSER "HTTPParser" +#define IOTJS_MAGIC_STRING_HTTP_VERSION_MAJOR "http_major" +#define IOTJS_MAGIC_STRING_HTTP_VERSION_MINOR "http_minor" +#if ENABLE_MODULE_GPIO #define IOTJS_MAGIC_STRING_IN "IN" -#define IOTJS_MAGIC_STRING_IOTJS_ENV "IOTJS_ENV" -#define IOTJS_MAGIC_STRING_IOTJS_PATH "IOTJS_PATH" +#endif +#define IOTJS_MAGIC_STRING__INCOMING "_incoming" +#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" #define IOTJS_MAGIC_STRING_ISALIVEEXCEPTFOR "isAliveExceptFor" #define IOTJS_MAGIC_STRING_ISDEVUP "isDevUp" +#define IOTJS_MAGIC_STRING_ISDIRECTORY "isDirectory" +#define IOTJS_MAGIC_STRING_ISFILE "isFile" +#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_LOOPBACK "loopback" +#if ENABLE_MODULE_SPI #define IOTJS_MAGIC_STRING_LSB "LSB" #define IOTJS_MAGIC_STRING_MAXSPEED "maxSpeed" +#endif +#if ENABLE_MODULE_MQTT || ENABLE_MODULE_WEBSOCKET +#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" #define IOTJS_MAGIC_STRING_MODE "mode" +#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_MQTTRECEIVE "MqttReceive" +#endif +#if ENABLE_MODULE_SPI #define IOTJS_MAGIC_STRING_MSB "MSB" -#define IOTJS_MAGIC_STRING_NATIVE_SOURCES "native_sources" -#define IOTJS_MAGIC_STRING_NONE "NONE" +#endif +#if ENABLE_MODULE_SPI || ENABLE_MODULE_GPIO +#define IOTJS_MAGIC_STRING_NONE_U "NONE" +#endif +#if ENABLE_MODULE_MQTT +#define IOTJS_MAGIC_STRING_ONACK "onack" +#endif #define IOTJS_MAGIC_STRING_ONBODY "OnBody" #define IOTJS_MAGIC_STRING_ONCLOSE "onclose" +#define IOTJS_MAGIC_STRING_ONCLOSED "onClosed" #define IOTJS_MAGIC_STRING_ONCONNECTION "onconnection" +#define IOTJS_MAGIC_STRING_ONDATA "onData" +#define IOTJS_MAGIC_STRING_ONEND "onEnd" +#define IOTJS_MAGIC_STRING_ONERROR "onError" +#if ENABLE_MODULE_TLS +#define IOTJS_MAGIC_STRING_ONHANDSHAKEDONE "onhandshakedone" +#endif #define IOTJS_MAGIC_STRING_ONHEADERSCOMPLETE "OnHeadersComplete" #define IOTJS_MAGIC_STRING_ONHEADERS "OnHeaders" #define IOTJS_MAGIC_STRING_ONMESSAGECOMPLETE "OnMessageComplete" #define IOTJS_MAGIC_STRING_ONMESSAGE "onmessage" #define IOTJS_MAGIC_STRING__ONNEXTTICK "_onNextTick" +#if ENABLE_MODULE_WEBSOCKET +#define IOTJS_MAGIC_STRING_ONPING "onping" +#endif +#if ENABLE_MODULE_MQTT || ENABLE_MODULE_WEBSOCKET +#define IOTJS_MAGIC_STRING_ONPINGRESP "onpingresp" +#endif +#if ENABLE_MODULE_MQTT +#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" +#define IOTJS_MAGIC_STRING_ONTIMEOUT "onTimeout" #define IOTJS_MAGIC_STRING__ONUNCAUGHTEXCEPTION "_onUncaughtException" -#define IOTJS_MAGIC_STRING_OPENDRAIN "OPENDRAIN" +#if ENABLE_MODULE_TLS +#define IOTJS_MAGIC_STRING_ONWRITE "onwrite" +#endif +#define IOTJS_MAGIC_STRING_ONWRITABLE "onWritable" +#if ENABLE_MODULE_GPIO +#define IOTJS_MAGIC_STRING_OPENDRAIN_U "OPENDRAIN" +#endif #define IOTJS_MAGIC_STRING_OPEN "open" -#define IOTJS_MAGIC_STRING_OUT "OUT" +#if ENABLE_MODULE_GPIO +#define IOTJS_MAGIC_STRING_OUT_U "OUT" +#endif #define IOTJS_MAGIC_STRING_OWNER "owner" +#if ENABLE_MODULE_WEBSOCKET +#define IOTJS_MAGIC_STRING_PARSEHANDSHAKEDATA "parseHandshakeData" +#endif +#if ENABLE_MODULE_MQTT +#define IOTJS_MAGIC_STRING_PASSWORD "password" +#endif #define IOTJS_MAGIC_STRING_PAUSE "pause" #define IOTJS_MAGIC_STRING_PERIOD "period" +#define IOTJS_MAGIC_STRING_PID "pid" #define IOTJS_MAGIC_STRING_PIN "pin" +#if ENABLE_MODULE_MQTT || ENABLE_MODULE_WEBSOCKET +#define IOTJS_MAGIC_STRING_PING "ping" +#endif #define IOTJS_MAGIC_STRING_PLATFORM "platform" +#if ENABLE_MODULE_WEBSOCKET +#define IOTJS_MAGIC_STRING_PONG "pong" +#endif #define IOTJS_MAGIC_STRING_PORT "port" +#if ENABLE_MODULE_WEBSOCKET +#define IOTJS_MAGIC_STRING_PREPAREHANDSHAKE "prepareHandshake" +#endif +#define IOTJS_MAGIC_STRING_PRIVATE "_private" #define IOTJS_MAGIC_STRING_PROTOTYPE "prototype" -#define IOTJS_MAGIC_STRING_PULLDOWN "PULLDOWN" -#define IOTJS_MAGIC_STRING_PULLUP "PULLUP" -#define IOTJS_MAGIC_STRING_PUSHPULL "PUSHPULL" +#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_READSTART "readStart" #define IOTJS_MAGIC_STRING_READSYNC "readSync" #define IOTJS_MAGIC_STRING_READUINT8 "readUInt8" +#if ENABLE_MODULE_DGRAM #define IOTJS_MAGIC_STRING_RECVSTART "recvStart" #define IOTJS_MAGIC_STRING_RECVSTOP "recvStop" +#endif #define IOTJS_MAGIC_STRING_REF "ref" -#define IOTJS_MAGIC_STRING_REINITIALIZE "reinitialize" +#if ENABLE_MODULE_TLS || ENABLE_MODULE_HTTPS +#define IOTJS_MAGIC_STRING_REJECTUNAUTHORIZED "rejectUnauthorized" +#endif +#if ENABLE_MODULE_MQTT +#define IOTJS_MAGIC_STRING_REMAINING "remaining" +#endif #define IOTJS_MAGIC_STRING_RENAME "rename" -#define IOTJS_MAGIC_STRING_REQUEST "REQUEST" -#define IOTJS_MAGIC_STRING_RESPONSE "RESPONSE" +#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" +#if ENABLE_MODULE_CRYPTO +#define IOTJS_MAGIC_STRING_RSAVERIFY "rsaVerify" +#endif #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" +#endif +#if ENABLE_MODULE_I2C #define IOTJS_MAGIC_STRING_SETADDRESS "setAddress" -#define IOTJS_MAGIC_STRING_SETBROADCAST "setBroadcast" +#endif +#if ENABLE_MODULE_UDP +#define IOTJS_MAGIC_STRING_CONFIGURE "configure" +#endif +#if ENABLE_MODULE_GPIO +#define IOTJS_MAGIC_STRING_SETDIRECTIONSYNC "setDirectionSync" +#endif +#if ENABLE_MODULE_PWM #define IOTJS_MAGIC_STRING_SETDUTYCYCLE "setDutyCycle" +#define IOTJS_MAGIC_STRING_SETDUTYCYCLESYNC "setDutyCycleSync" #define IOTJS_MAGIC_STRING_SETENABLE "setEnable" -#define IOTJS_MAGIC_STRING_SETFILTER "setFilter" +#define IOTJS_MAGIC_STRING_SETENABLESYNC "setEnableSync" #define IOTJS_MAGIC_STRING_SETFREQUENCY "setFrequency" +#define IOTJS_MAGIC_STRING_SETFREQUENCYSYNC "setFrequencySync" +#endif +#if ENABLE_MODULE_BLE +#define IOTJS_MAGIC_STRING_SETFILTER "setFilter" +#endif #define IOTJS_MAGIC_STRING_SETKEEPALIVE "setKeepAlive" -#define IOTJS_MAGIC_STRING_SETMULTICASTLOOPBACK "setMulticastLoopback" -#define IOTJS_MAGIC_STRING_SETMULTICASTTTL "setMulticastTTL" +#if ENABLE_MODULE_PWM #define IOTJS_MAGIC_STRING_SETPERIOD "setPeriod" -#define IOTJS_MAGIC_STRING_SETTTL "setTTL" +#define IOTJS_MAGIC_STRING_SETPERIODSYNC "setPeriodSync" +#endif +#define IOTJS_MAGIC_STRING_SETTIMEOUT "setTimeout" +#if ENABLE_MODULE_CRYPTO +#define IOTJS_MAGIC_STRING_SHAENCODE "shaEncode" +#endif #define IOTJS_MAGIC_STRING_SHOULDKEEPALIVE "shouldkeepalive" #define IOTJS_MAGIC_STRING_SHUTDOWN "shutdown" #define IOTJS_MAGIC_STRING_SLICE "slice" +#if ENABLE_MODULE_SPI #define IOTJS_MAGIC_STRING_SPI "Spi" +#endif #define IOTJS_MAGIC_STRING_START "start" #define IOTJS_MAGIC_STRING_STAT "stat" +#define IOTJS_MAGIC_STRING_STATS "stats" #define IOTJS_MAGIC_STRING_STATUS_MSG "status_msg" #define IOTJS_MAGIC_STRING_STATUS "status" #define IOTJS_MAGIC_STRING_STDERR "stderr" #define IOTJS_MAGIC_STRING_STDOUT "stdout" #define IOTJS_MAGIC_STRING_STOP "stop" -#define IOTJS_MAGIC_STRING_TOHEXSTRING "toHexString" +#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" -#define IOTJS_MAGIC_STRING_TRANSFERARRAY "transferArray" -#define IOTJS_MAGIC_STRING_TRANSFERBUFFER "transferBuffer" -#define IOTJS_MAGIC_STRING_UNEXPORT "unexport" +#if ENABLE_MODULE_SPI +#define IOTJS_MAGIC_STRING_TRANSFER "transfer" +#define IOTJS_MAGIC_STRING_TRANSFERSYNC "transferSync" +#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_WRITESYNC "writeSync" +#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" +#define IOTJS_MAGIC_STRING_WRITESYNC "writeSync" +#if ENABLE_MODULE_HTTPS +#define IOTJS_MAGIC_STRING__WRITE "_write" +#endif +#if ENABLE_MODULE_WEBSOCKET +#define IOTJS_MAGIC_STRING_WSINIT "wsInit" +#define IOTJS_MAGIC_STRING_WSRECEIVE "wsReceive" +#define IOTJS_MAGIC_STRING_WSRECEIVEHANDSHAKEDATA "ReceiveHandshakeData" +#endif +#if ENABLE_MODULE_BRIDGE +#define IOTJS_MAGIC_STRING_MODULE_NAME "MODULE_NAME" +#endif +#if ENABLE_MODULE_TIZEN +#define IOTJS_MAGIC_STRING_TIZEN "tizen" +#define IOTJS_MAGIC_STRING_APP_CONTROL "appControl" +#endif +#if ENABLE_MODULE_NAPI +#define IOTJS_MAGIC_STRING_ERROR "Error" +#endif -#endif /* IOTJS_STRING_CONSTANTS_H */ +#endif /* IOTJS_MAGIC_STRINGS_H */ diff --git a/src/iotjs_module.c b/src/iotjs_module.c index 20a8080ae4..b9a7fbf9d2 100644 --- a/src/iotjs_module.c +++ b/src/iotjs_module.c @@ -13,66 +13,39 @@ * limitations under the License. */ - #include "iotjs_def.h" #include "iotjs_module.h" +typedef struct { jerry_value_t jmodule; } iotjs_module_rw_data_t; -typedef struct { - ModuleKind kind; - iotjs_jval_t jmodule; - register_func fn_register; -} iotjs_module_t; - - -static iotjs_module_t modules[MODULE_COUNT]; - - -#define DECLARE_MODULE_INITIALIZER(upper, Camel, lower) \ - iotjs_jval_t Init##Camel(); - -MAP_MODULE_LIST(DECLARE_MODULE_INITIALIZER) - -#undef DECLARE_MODULE_INITIALIZER - - -#define INIT_MODULE_LIST(upper, Camel, lower) \ - modules[MODULE_##upper].kind = MODULE_##upper; \ - modules[MODULE_##upper].jmodule = *iotjs_jval_get_undefined(); \ - modules[MODULE_##upper].fn_register = Init##Camel; - -void iotjs_module_list_init() { - MAP_MODULE_LIST(INIT_MODULE_LIST) -} - -#undef INIT_MODULE_LIST - +#include "iotjs_module_inl.h" -#define CLENUP_MODULE_LIST(upper, Camel, lower) \ - if (!iotjs_jval_is_undefined(&modules[MODULE_##upper].jmodule)) \ - iotjs_jval_destroy(&modules[MODULE_##upper].jmodule); +/** + * iotjs_module_inl.h provides: + * - iotjs_module_count + * - iotjs_module_ro_data[] + * - iotjs_module_rw_data[] + */ -void iotjs_module_list_cleanup() { - MAP_MODULE_LIST(CLENUP_MODULE_LIST) +void iotjs_module_list_cleanup(void) { + for (unsigned i = 0; i < iotjs_module_count; i++) { + if (iotjs_module_rw_data[i].jmodule != 0) { + jerry_release_value(iotjs_module_rw_data[i].jmodule); + iotjs_module_rw_data[i].jmodule = 0; + } + } } -#undef CLENUP_MODULE_LIST +jerry_value_t iotjs_module_get(const char* name) { + for (unsigned i = 0; i < iotjs_module_count; i++) { + if (!strcmp(name, iotjs_module_ro_data[i].name)) { + if (iotjs_module_rw_data[i].jmodule == 0) { + iotjs_module_rw_data[i].jmodule = iotjs_module_ro_data[i].fn_register(); + } - -const iotjs_jval_t* iotjs_module_initialize_if_necessary(ModuleKind kind) { - IOTJS_ASSERT(kind < MODULE_COUNT); - IOTJS_ASSERT(&modules[kind].fn_register != NULL); - - if (iotjs_jval_is_undefined(&modules[kind].jmodule)) { - modules[kind].jmodule = modules[kind].fn_register(); + return iotjs_module_rw_data[i].jmodule; + } } - return iotjs_module_get(kind); -} - - -const iotjs_jval_t* iotjs_module_get(ModuleKind kind) { - IOTJS_ASSERT(kind < MODULE_COUNT); - IOTJS_ASSERT(!iotjs_jval_is_undefined(&modules[kind].jmodule)); - return &modules[kind].jmodule; + return jerry_create_undefined(); } diff --git a/src/iotjs_module.h b/src/iotjs_module.h index fb880b10d3..74a0f40916 100644 --- a/src/iotjs_module.h +++ b/src/iotjs_module.h @@ -18,58 +18,18 @@ #include "iotjs_binding.h" +typedef jerry_value_t (*register_func)(void); -typedef iotjs_jval_t (*register_func)(); +typedef struct { + const char* name; + register_func fn_register; +} iotjs_module_ro_data_t; +extern const unsigned iotjs_module_count; +extern const iotjs_module_ro_data_t iotjs_module_ro_data[]; -#define CONCATENATE(x, ...) x##__VA_ARGS__ - -#define IF(c) CONCATENATE(IF_, c) -#define IF_1(expr) expr -#define IF_0(expr) - -// Check if specific module is enabled -#define E(F, UPPER, Camel, lower) \ - IF(ENABLE_MODULE_##UPPER)(F(UPPER, Camel, lower)) - -// List of builtin modules -#define MAP_MODULE_LIST(F) \ - E(F, ADC, Adc, adc) \ - E(F, BLEHCISOCKET, Blehcisocket, blehcisocket) \ - E(F, BUFFER, Buffer, buffer) \ - E(F, CONSOLE, Console, console) \ - E(F, CONSTANTS, Constants, constants) \ - E(F, DNS, Dns, dns) \ - E(F, FS, Fs, fs) \ - E(F, GPIO, Gpio, gpio) \ - E(F, HTTPPARSER, Httpparser, httpparser) \ - E(F, I2C, I2c, i2c) \ - E(F, PROCESS, Process, process) \ - E(F, PWM, Pwm, pwm) \ - E(F, SPI, Spi, spi) \ - E(F, STM32F4DIS, Stm32f4dis, stm32f4dis) \ - E(F, TESTDRIVER, Testdriver, testdriver) \ - E(F, TCP, Tcp, tcp) \ - E(F, TIMER, Timer, timer) \ - E(F, UART, Uart, uart) \ - E(F, UDP, Udp, udp) - -#define ENUMDEF_MODULE_LIST(upper, Camel, lower) MODULE_##upper, - -typedef enum { - MAP_MODULE_LIST(ENUMDEF_MODULE_LIST) // enumerate modules - MODULE_COUNT, -} ModuleKind; - -#undef ENUMDEF_MODULE_LIST - - -void iotjs_module_list_init(); - -void iotjs_module_list_cleanup(); - -const iotjs_jval_t* iotjs_module_initialize_if_necessary(ModuleKind kind); -const iotjs_jval_t* iotjs_module_get(ModuleKind kind); +void iotjs_module_list_cleanup(void); +jerry_value_t iotjs_module_get(const char* name); #endif /* IOTJS_MODULE_H */ diff --git a/src/iotjs_objectwrap.c b/src/iotjs_objectwrap.c deleted file mode 100644 index 66b22fbc2d..0000000000 --- a/src/iotjs_objectwrap.c +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright 2015-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_def.h" -#include "iotjs_objectwrap.h" - - -void iotjs_jobjectwrap_initialize(iotjs_jobjectwrap_t* jobjectwrap, - const iotjs_jval_t* jobject, - JNativeInfoType native_info) { - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_jobjectwrap_t, jobjectwrap); - - IOTJS_ASSERT(iotjs_jval_is_object(jobject)); - - // This wrapper holds pointer to the javascript object but never increases - // reference count. - _this->jobject = *((iotjs_jval_t*)jobject); - - // Set native pointer of the object to be this wrapper. - // If the object is freed by GC, the wrapper instance should also be freed. - iotjs_jval_set_object_native_handle(&_this->jobject, (uintptr_t)jobjectwrap, - native_info); -} - - -void iotjs_jobjectwrap_destroy(iotjs_jobjectwrap_t* jobjectwrap) { - IOTJS_VALIDATABLE_STRUCT_DESTRUCTOR_VALIDATE(iotjs_jobjectwrap_t, - jobjectwrap); - /* Do nothing on _this->jobject */ -} - - -iotjs_jval_t* iotjs_jobjectwrap_jobject(iotjs_jobjectwrap_t* jobjectwrap) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_jobjectwrap_t, jobjectwrap); - iotjs_jval_t* jobject = &_this->jobject; - IOTJS_ASSERT((uintptr_t)jobjectwrap == - iotjs_jval_get_object_native_handle(jobject)); - IOTJS_ASSERT(iotjs_jval_is_object(jobject)); - return jobject; -} - - -iotjs_jobjectwrap_t* iotjs_jobjectwrap_from_jobject( - const iotjs_jval_t* jobject) { - iotjs_jobjectwrap_t* wrap = - (iotjs_jobjectwrap_t*)(iotjs_jval_get_object_native_handle(jobject)); - IOTJS_ASSERT(iotjs_jval_is_object(iotjs_jobjectwrap_jobject(wrap))); - return wrap; -} diff --git a/src/iotjs_objectwrap.h b/src/iotjs_objectwrap.h deleted file mode 100644 index 5d51b27929..0000000000 --- a/src/iotjs_objectwrap.h +++ /dev/null @@ -1,50 +0,0 @@ -/* Copyright 2015-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_OBJECTWRAP_H -#define IOTJS_OBJECTWRAP_H - - -#include "iotjs_binding.h" - - -// This wrapper refer javascript object but never increase reference count -// If the object is freed by GC, then this wrapper instance will be also freed. -typedef struct { - iotjs_jval_t jobject; -} IOTJS_VALIDATED_STRUCT(iotjs_jobjectwrap_t); - -void iotjs_jobjectwrap_initialize(iotjs_jobjectwrap_t* jobjectwrap, - const iotjs_jval_t* jobject, - JNativeInfoType native_info); - -void iotjs_jobjectwrap_destroy(iotjs_jobjectwrap_t* jobjectwrap); - -iotjs_jval_t* iotjs_jobjectwrap_jobject(iotjs_jobjectwrap_t* jobjectwrap); -iotjs_jobjectwrap_t* iotjs_jobjectwrap_from_jobject( - const iotjs_jval_t* jobject); - -#define IOTJS_DEFINE_NATIVE_HANDLE_INFO(module) \ - static const jerry_object_native_info_t module##_native_info = { \ - .free_cb = (jerry_object_native_free_callback_t)iotjs_##module##_destroy \ - } - -#define IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(name) \ - static void iotjs_##name##_destroy(iotjs_##name##_t* wrap); \ - static const jerry_object_native_info_t this_module_native_info = { \ - .free_cb = (jerry_object_native_free_callback_t)iotjs_##name##_destroy \ - } - -#endif /* IOTJS_OBJECTWRAP_H */ diff --git a/src/iotjs_reqwrap.c b/src/iotjs_reqwrap.c deleted file mode 100644 index ae9037fed4..0000000000 --- a/src/iotjs_reqwrap.c +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright 2015-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_def.h" -#include "iotjs_reqwrap.h" - - -void iotjs_reqwrap_initialize(iotjs_reqwrap_t* reqwrap, - const iotjs_jval_t* jcallback, - uv_req_t* request) { - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_reqwrap_t, reqwrap); - IOTJS_ASSERT(iotjs_jval_is_function(jcallback)); - _this->jcallback = iotjs_jval_create_copied(jcallback); - _this->request = request; - _this->request->data = reqwrap; -} - - -void iotjs_reqwrap_destroy(iotjs_reqwrap_t* reqwrap) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_reqwrap_t, reqwrap); - iotjs_jval_destroy(&_this->jcallback); -} - - -static void iotjs_reqwrap_validate(iotjs_reqwrap_t* reqwrap) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_reqwrap_t, reqwrap); - IOTJS_ASSERT(_this->request->data == reqwrap); -} - - -const iotjs_jval_t* iotjs_reqwrap_jcallback(iotjs_reqwrap_t* reqwrap) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_reqwrap_t, reqwrap); - iotjs_reqwrap_validate(reqwrap); - return &_this->jcallback; -} - - -uv_req_t* iotjs_reqwrap_req(iotjs_reqwrap_t* reqwrap) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_reqwrap_t, reqwrap); - iotjs_reqwrap_validate(reqwrap); - return _this->request; -} - - -iotjs_reqwrap_t* iotjs_reqwrap_from_request(uv_req_t* req) { - iotjs_reqwrap_t* reqwrap = req->data; - iotjs_reqwrap_validate(reqwrap); - return reqwrap; -} diff --git a/src/iotjs_reqwrap.h b/src/iotjs_reqwrap.h deleted file mode 100644 index 3fb99acafb..0000000000 --- a/src/iotjs_reqwrap.h +++ /dev/null @@ -1,50 +0,0 @@ -/* Copyright 2015-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_REQWRAP_H -#define IOTJS_REQWRAP_H - - -#include - -#include "iotjs_binding.h" - - -// UV request wrapper. -// Wrapping UV request and JavaScript callback. -// When an instance of request wrapper is created. it will increase ref count -// for JavaScript callback function to prevent it from reclaimed by GC. The -// reference count will decrease back when wrapper is being freed. -typedef struct { - iotjs_jval_t jcallback; - uv_req_t* request; -} IOTJS_VALIDATED_STRUCT(iotjs_reqwrap_t); - - -void iotjs_reqwrap_initialize(iotjs_reqwrap_t* reqwrap, - const iotjs_jval_t* jcallback, uv_req_t* request); -void iotjs_reqwrap_destroy(iotjs_reqwrap_t* reqwrap); - -// To retrieve javascript callback function object. -const iotjs_jval_t* iotjs_reqwrap_jcallback(iotjs_reqwrap_t* reqwrap); - -// To retrieve pointer to uv request. -uv_req_t* iotjs_reqwrap_req(iotjs_reqwrap_t* reqwrap); - - -iotjs_reqwrap_t* iotjs_reqwrap_from_request(uv_req_t* req); - - -#endif /* IOTJS_REQWRAP_H */ diff --git a/src/iotjs_string.c b/src/iotjs_string.c index 839b29d379..27b4fa7be0 100644 --- a/src/iotjs_string.c +++ b/src/iotjs_string.c @@ -21,12 +21,11 @@ #include -iotjs_string_t iotjs_string_create() { +iotjs_string_t iotjs_string_create(void) { iotjs_string_t str; - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_string_t, &str); - _this->size = 0; - _this->data = NULL; + str.size = 0; + str.data = NULL; return str; } @@ -34,16 +33,14 @@ iotjs_string_t iotjs_string_create() { iotjs_string_t iotjs_string_create_with_size(const char* data, size_t size) { iotjs_string_t str; - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_string_t, &str); - _this->size = size; + str.size = size; - if (size > 0) { - IOTJS_ASSERT(data != NULL); - _this->data = iotjs_buffer_allocate(size); - memcpy(_this->data, data, size); + if (data && size > 0) { + str.data = iotjs_buffer_allocate(size); + memcpy(str.data, data, size); } else { - _this->data = NULL; + str.data = NULL; } return str; @@ -52,15 +49,14 @@ iotjs_string_t iotjs_string_create_with_size(const char* data, size_t size) { iotjs_string_t iotjs_string_create_with_buffer(char* buffer, size_t size) { iotjs_string_t str; - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_string_t, &str); - _this->size = size; + str.size = size; if (size > 0) { IOTJS_ASSERT(buffer != NULL); - _this->data = buffer; + str.data = buffer; } else { - _this->data = NULL; + str.data = NULL; } return str; @@ -68,65 +64,43 @@ iotjs_string_t iotjs_string_create_with_buffer(char* buffer, size_t size) { void iotjs_string_destroy(iotjs_string_t* str) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_string_t, str); - - if (_this->data != NULL) { - iotjs_buffer_release(_this->data); - _this->size = 0; - } + IOTJS_RELEASE(str->data); + str->size = 0; } bool iotjs_string_is_empty(const iotjs_string_t* str) { - const IOTJS_VALIDATED_STRUCT_METHOD(iotjs_string_t, str); - - return _this->size == 0; + return str->size == 0; } - -void iotjs_string_make_empty(iotjs_string_t* str) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_string_t, str); - - if (_this->data != NULL) { - iotjs_buffer_release(_this->data); - _this->size = 0; - _this->data = NULL; - } -} - - void iotjs_string_append(iotjs_string_t* str, const char* data, size_t size) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_string_t, str); - IOTJS_ASSERT(data != NULL); - if (size == 0) { + if (data == NULL || size == 0) { return; } - if (_this->data != NULL) { - _this->data = iotjs_buffer_reallocate(_this->data, _this->size + size); + if (str->data != NULL) { + str->data = iotjs_buffer_reallocate(str->data, str->size + size); } else { - IOTJS_ASSERT(_this->size == 0); - _this->data = iotjs_buffer_allocate(size); + IOTJS_ASSERT(str->size == 0); + str->data = iotjs_buffer_allocate(size); } - memcpy(_this->data + _this->size, data, size); - _this->size += size; + memcpy(str->data + str->size, data, size); + str->size += size; } const char* iotjs_string_data(const iotjs_string_t* str) { - const IOTJS_VALIDATED_STRUCT_METHOD(iotjs_string_t, str); - if (_this->data == NULL) { + if (str->data == NULL) { return ""; } - return _this->data; + return str->data; } unsigned iotjs_string_size(const iotjs_string_t* str) { - const IOTJS_VALIDATED_STRUCT_METHOD(iotjs_string_t, str); - return _this->size; + return str->size; } diff --git a/src/iotjs_string.h b/src/iotjs_string.h index 19d0e2d4d4..dff3a1e90d 100644 --- a/src/iotjs_string.h +++ b/src/iotjs_string.h @@ -16,14 +16,15 @@ #ifndef IOTJS_STRING_H #define IOTJS_STRING_H +#include typedef struct { size_t size; char* data; -} IOTJS_VALIDATED_STRUCT(iotjs_string_t); +} iotjs_string_t; // Create new string -iotjs_string_t iotjs_string_create(); +iotjs_string_t iotjs_string_create(void); iotjs_string_t iotjs_string_create_with_size(const char* data, size_t size); iotjs_string_t iotjs_string_create_with_buffer(char* buffer, size_t size); @@ -33,9 +34,6 @@ void iotjs_string_destroy(iotjs_string_t* str); // Check if string is empty bool iotjs_string_is_empty(const iotjs_string_t* str); -// Make string empty -void iotjs_string_make_empty(iotjs_string_t* str); - // Append `data` to tail of the string. void iotjs_string_append(iotjs_string_t* str, const char* data, size_t size); diff --git a/src/iotjs_string_ext.c b/src/iotjs_string_ext.c index 9cadefbac5..4f28c420b3 100644 --- a/src/iotjs_string_ext.c +++ b/src/iotjs_string_ext.c @@ -48,9 +48,9 @@ static const jerry_length_t magic_string_lengths[] = { // // declare strings table // -static const jerry_char_ptr_t magic_string_items[] = { +static const jerry_char_t *const magic_string_items[] = { #define MAGICSTR_EX_DEF(NAME, STRING) \ - (const jerry_char_ptr_t) jerry_magic_string_ex_##NAME, + (const jerry_char_t *)jerry_magic_string_ex_##NAME, JERRY_MAGIC_STRING_ITEMS @@ -60,7 +60,7 @@ static const jerry_char_ptr_t magic_string_items[] = { void iotjs_register_jerry_magic_string(void) { uint32_t num_magic_string_items = - (uint32_t)(sizeof(magic_string_items) / sizeof(jerry_char_ptr_t)); + (uint32_t)(sizeof(magic_string_items) / sizeof(jerry_char_t *)); jerry_register_magic_strings(magic_string_items, num_magic_string_items, magic_string_lengths); } diff --git a/src/iotjs_util.c b/src/iotjs_util.c index 62ca2147e0..a3a2fc6b4b 100644 --- a/src/iotjs_util.c +++ b/src/iotjs_util.c @@ -21,16 +21,33 @@ #include #include +#if defined(__linux__) && !defined(__OPENWRT__) +#include +#endif + +void force_terminate(void); iotjs_string_t iotjs_file_read(const char* path) { FILE* file = fopen(path, "rb"); - IOTJS_ASSERT(file != NULL); + if (file == NULL) { + iotjs_string_t empty_content = iotjs_string_create(); + return empty_content; + } - fseek(file, 0, SEEK_END); + int fseek_ret = fseek(file, 0, SEEK_END); + IOTJS_ASSERT(fseek_ret == 0); long ftell_ret = ftell(file); IOTJS_ASSERT(ftell_ret >= 0); size_t len = (size_t)ftell_ret; - fseek(file, 0, SEEK_SET); + 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); @@ -60,18 +77,81 @@ 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; +} + + +char* iotjs_buffer_allocate_from_number_array(size_t size, + const jerry_value_t array) { + char* buffer = iotjs_buffer_allocate(size); + for (size_t i = 0; i < size; i++) { + jerry_value_t jdata = iotjs_jval_get_property_by_index(array, i); + buffer[i] = iotjs_jval_as_number(jdata); + jerry_release_value(jdata); + } return buffer; } 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; } void iotjs_buffer_release(char* buffer) { - IOTJS_ASSERT(buffer != NULL); - free(buffer); + if (buffer) { + free(buffer); + } +} + +void print_stacktrace(void) { +#if !defined(NDEBUG) && defined(__linux__) && defined(DEBUG) && \ + !defined(__OPENWRT__) + // TODO: support other platforms + const int numOfStackTrace = 100; + void* buffer[numOfStackTrace]; + char command[256]; + + int nptrs = backtrace(buffer, numOfStackTrace); + char** strings = backtrace_symbols(buffer, nptrs); + + if (strings == NULL) { + perror("backtrace_symbols"); + exit(EXIT_FAILURE); + } + + printf("\n[Backtrace]:\n"); + for (int j = 0; j < nptrs - 2; j++) { // remove the last two + int idx = 0; + while (strings[j][idx] != '\0') { + if (strings[j][idx] == '(') { + break; + } + idx++; + } + snprintf(command, sizeof(command), "addr2line %p -e %.*s", buffer[j], idx, + strings[j]); + + if (system(command)) { + break; + } + } + + free(strings); +#endif // !defined(NDEBUG) && defined(__linux__) && defined(DEBUG) && + // !defined(__OPENWRT__) +} + +void force_terminate(void) { + exit(EXIT_FAILURE); } diff --git a/src/iotjs_util.h b/src/iotjs_util.h index e7e18968c8..6d3d64c122 100644 --- a/src/iotjs_util.h +++ b/src/iotjs_util.h @@ -18,20 +18,30 @@ #include "iotjs_string.h" - +#include "jerryscript.h" // Return value should be released with iotjs_string_destroy() iotjs_string_t iotjs_file_read(const char* path); char* iotjs_buffer_allocate(size_t size); +char* iotjs_buffer_allocate_from_number_array(size_t size, + const jerry_value_t array); char* iotjs_buffer_reallocate(char* buffer, size_t size); void iotjs_buffer_release(char* buff); +void print_stacktrace(void); + #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) + do { \ + iotjs_buffer_release((char*)ptr); \ + ptr = NULL; \ + } while (0) #endif /* IOTJS_UTIL_H */ diff --git a/src/iotjs_uv_handle.c b/src/iotjs_uv_handle.c new file mode 100644 index 0000000000..defa162292 --- /dev/null +++ b/src/iotjs_uv_handle.c @@ -0,0 +1,68 @@ +/* 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_def.h" + +#include "iotjs_uv_handle.h" + + +uv_handle_t* iotjs_uv_handle_create(size_t handle_size, + const jerry_value_t jobject, + JNativeInfoType* native_info, + size_t extra_data_size) { + IOTJS_ASSERT(jerry_value_is_object(jobject)); + + /* Make sure that the jerry_value_t is aligned */ + size_t aligned_request_size = IOTJS_ALIGNUP(handle_size, 8u); + + char* request_memory = iotjs_buffer_allocate( + aligned_request_size + sizeof(iotjs_uv_handle_data) + extra_data_size); + uv_handle_t* uv_handle = (uv_handle_t*)request_memory; + uv_handle->data = request_memory + aligned_request_size; + + IOTJS_UV_HANDLE_DATA(uv_handle)->jobject = jobject; + IOTJS_UV_HANDLE_DATA(uv_handle)->on_close_cb = NULL; + jerry_acquire_value(jobject); + + jerry_set_object_native_pointer(jobject, uv_handle, native_info); + + return uv_handle; +} + + +static void iotjs_uv_handle_close_processor(uv_handle_t* handle) { + iotjs_uv_handle_data* handle_data = IOTJS_UV_HANDLE_DATA(handle); + + if (handle_data->on_close_cb != NULL) { + handle_data->on_close_cb(handle); + } + + // Decrease ref count of Javascript object. From now the object can be + // reclaimed. + jerry_release_value(handle_data->jobject); + IOTJS_RELEASE(handle); +} + + +void iotjs_uv_handle_close(uv_handle_t* handle, OnCloseHandler close_handler) { + if (handle == NULL || uv_is_closing(handle)) { + DDLOG("Attempt to close uninitialized or already closed handle"); + return; + } + + iotjs_uv_handle_data* handle_data = IOTJS_UV_HANDLE_DATA(handle); + handle_data->on_close_cb = close_handler; + uv_close(handle, iotjs_uv_handle_close_processor); +} diff --git a/src/iotjs_uv_handle.h b/src/iotjs_uv_handle.h new file mode 100644 index 0000000000..570ff28a29 --- /dev/null +++ b/src/iotjs_uv_handle.h @@ -0,0 +1,75 @@ +/* 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_UV_HANDLE +#define IOTJS_UV_HANDLE + +#include + +#include "iotjs_binding.h" + +typedef void (*OnCloseHandler)(uv_handle_t*); + +typedef struct { + jerry_value_t jobject; + OnCloseHandler on_close_cb; +} iotjs_uv_handle_data; + +#define IOTJS_ALIGNUP(value, alignment) \ + (((value) + ((alignment)-1)) & ~((alignment)-1)) + +/** + * Allocate and initialize an uv_handle_t structure with a jerry callback and + * extra data. + * + * The allocated memory has the following layout: + * + * |-------------| <- start of uv_handle_t* + * | uv_handle_t | + * | | + * |-------------| + * | PADDING | <- alignment padding + * |-------------| <- start of the iotjs_uv_handle_data struct + * | handle_data | + * |-------------| <- start of the extra data if required + * | extra | + * |-------------| + * + */ +uv_handle_t* iotjs_uv_handle_create(size_t handle_size, + const jerry_value_t jobject, + JNativeInfoType* native_info, + size_t extra_data_size); +void iotjs_uv_handle_close(uv_handle_t* handle, OnCloseHandler close_handler); + +/** + * Returns a pointer to the handle data struct referenced + * by the uv_handle_t->data member. + */ +#define IOTJS_UV_HANDLE_DATA(UV_HANDLE) \ + ((iotjs_uv_handle_data*)((UV_HANDLE)->data)) + +/** + * Returns a char* pointer for any extra data. + * + * IMPORTANT! + * Make sure that the extra data is correctly allocated by using the + * iotjs_uv_handle_create method call. + */ +#define IOTJS_UV_HANDLE_EXTRA_DATA(UV_HANDLE) \ + ((char*)((char*)((UV_HANDLE)->data) + sizeof(iotjs_uv_handle_data))) + + +#endif /* IOTJS_UV_HANDLE */ diff --git a/src/iotjs_uv_request.c b/src/iotjs_uv_request.c new file mode 100644 index 0000000000..77acdeea08 --- /dev/null +++ b/src/iotjs_uv_request.c @@ -0,0 +1,53 @@ +/* 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_uv_request.h" + +#include "iotjs_def.h" + +/** + * Aligns @a value to @a alignment. @a must be the power of 2. + * + * Returns minimum positive value, that divides @a alignment and is more than or + * equal to @a value + */ +#define IOTJS_ALIGNUP(value, alignment) \ + (((value) + ((alignment)-1)) & ~((alignment)-1)) + + +uv_req_t* iotjs_uv_request_create(size_t request_size, + const jerry_value_t jcallback, + size_t extra_data_size) { + IOTJS_ASSERT(jerry_value_is_function(jcallback)); + + /* Make sure that the jerry_value_t is aligned */ + size_t aligned_request_size = IOTJS_ALIGNUP(request_size, 8u); + + char* request_memory = iotjs_buffer_allocate( + aligned_request_size + sizeof(jerry_value_t) + extra_data_size); + uv_req_t* uv_request = (uv_req_t*)request_memory; + uv_request->data = request_memory + aligned_request_size; + + *IOTJS_UV_REQUEST_JSCALLBACK(uv_request) = jcallback; + jerry_acquire_value(jcallback); + + return uv_request; +} + + +void iotjs_uv_request_destroy(uv_req_t* request) { + jerry_release_value(*IOTJS_UV_REQUEST_JSCALLBACK(request)); + IOTJS_RELEASE(request); +} diff --git a/src/iotjs_uv_request.h b/src/iotjs_uv_request.h new file mode 100644 index 0000000000..a4de22beed --- /dev/null +++ b/src/iotjs_uv_request.h @@ -0,0 +1,61 @@ +/* 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_UV_REQUEST +#define IOTJS_UV_REQUEST + +#include + +#include "iotjs_binding.h" + +/** + * Allocate and initialize an uv_req_t structure with a jerry callback and extra + * data. + * + * The allocated memory has the following layout: + * + * |----------| <- start of uv_req_t* + * | uv_req_t | + * | | + * |----------| + * | PADDING | <- alignment padding + * |----------| <- start of jerry_value_t* which is the callback + * | callback | + * |----------| <- start of the extra data if required + * | extra | + * |----------| + * + */ +uv_req_t* iotjs_uv_request_create(size_t request_size, + const jerry_value_t jcallback, + size_t extra_data_size); +void iotjs_uv_request_destroy(uv_req_t* request); + +/** + * Returns a pointer to the js callback referenced by the uv_req_t->data member. + */ +#define IOTJS_UV_REQUEST_JSCALLBACK(UV_REQ) ((jerry_value_t*)(UV_REQ->data)) + +/** + * Returns a char* pointer for any extra data. + * + * IMPORTANT! + * Make sure that the extra data is correctly allocated via the + * iotjs_uv_request_create method call. + */ +#define IOTJS_UV_REQUEST_EXTRA_DATA(UV_REQ) \ + ((char*)((char*)(UV_REQ->data) + sizeof(jerry_value_t))) + +#endif /* IOTJS_UV_REQUEST */ diff --git a/src/js/adc.js b/src/js/adc.js index fbde401cbc..20c322bbc7 100644 --- a/src/js/adc.js +++ b/src/js/adc.js @@ -13,102 +13,16 @@ * limitations under the License. */ -var util = require('util'); -var adc = process.binding(process.binding.adc); - - -function Adc() { - if (!(this instanceof Adc)) { - return new Adc(); - } -} - -Adc.prototype.open = function(configuration, callback) { - return adcPinOpen(configuration, callback); -}; - - -function adcPinOpen(configuration, callback) { - var _binding = null; - - function AdcPin(configuration, callback) { - var self = this; - - if (util.isObject(configuration)) { - if (process.platform === 'linux') { - if (!util.isString(configuration.device)) { - throw new TypeError( - 'Bad configuration - device is mandatory and should be String'); - } - } else if (process.platform === 'nuttx') { - if (!util.isNumber(configuration.pin)) { - throw new TypeError( - 'Bad configuration - pin is mandatory and should be Number'); - } - } - } else { - throw new TypeError('Bad arguments - configuration should be Object') - } - - _binding = new adc.Adc(configuration, function(err) { - util.isFunction(callback) && callback.call(self, err); - }); - - process.on('exit', (function(self) { - return function() { - if (!util.isNull(_binding)) { - self.closeSync(); - } - }; - })(this)); - } - - AdcPin.prototype.read = function(callback) { - var self = this; - - if (util.isNull(_binding)) { - throw new Error('ADC pin is not opened'); - } - - _binding.read(function(err, value) { - util.isFunction(callback) && callback.call(self, err, value); +var adc = { + open: function(config, callback) { + var adcPin = new native(config, function(err) { + callback(err, adcPin); }); - }; - - AdcPin.prototype.readSync = function() { - if (util.isNull(_binding)) { - throw new Error('ADC pin is not opened'); - } - - return _binding.read(); - }; - - AdcPin.prototype.close = function(callback) { - var self = this; - - if (util.isNull(_binding)) { - throw new Error('ADC pin is not opened'); - } - - _binding.close(function(err) { - util.isFunction(callback) && callback.call(self, err); - }); - - _binding = null; - }; - - AdcPin.prototype.closeSync = function() { - if (util.isNull(_binding)) { - throw new Error('ADC pin is not opened'); - } - - _binding.close(); - - _binding = null; - }; - - return new AdcPin(configuration, callback); -} - + return adcPin; + }, + openSync: function(config) { + return new native(config); + }, +}; -module.exports = Adc; +module.exports = adc; diff --git a/src/js/assert.js b/src/js/assert.js index 639642a093..97b715fad7 100644 --- a/src/js/assert.js +++ b/src/js/assert.js @@ -69,7 +69,7 @@ function fail(actual, expected, message, operator) { message: message, actual: actual, expected: expected, - operator: operator + operator: operator, }); } diff --git a/src/js/ble.js b/src/js/ble.js index f928004235..3a1b35a5ea 100644 --- a/src/js/ble.js +++ b/src/js/ble.js @@ -39,7 +39,7 @@ var debug = console.log; // require('debug')('ble'); var events = require('events'); var util = require('util'); -var UuidUtil = require('ble_uuid_util'); +var uuidUtil = require('ble_uuid_util'); var PrimaryService = require('ble_primary_service'); var Characteristic = require('ble_characteristic'); @@ -143,7 +143,7 @@ Bleno.prototype.startAdvertising = function(name, serviceUuids, callback) { if (serviceUuids && serviceUuids.length) { for (var i = 0; i < serviceUuids.length; i++) { - undashedServiceUuids[i] = UuidUtil.removeDashes(serviceUuids[i]); + undashedServiceUuids[i] = uuidUtil.removeDashes(serviceUuids[i]); } } @@ -161,7 +161,7 @@ Bleno.prototype.startAdvertisingIBeacon = function(uuid, major, minor, measuredP throw error; } } else { - var undashedUuid = UuidUtil.removeDashes(uuid); + var undashedUuid = uuidUtil.removeDashes(uuid); var uuidData = new Buffer(undashedUuid, 'hex'); var uuidDataLength = uuidData.length; var iBeaconData = new Buffer(uuidData.length + 5); diff --git a/src/js/ble_characteristic.js b/src/js/ble_characteristic.js index d21a36744e..cf54e5bb91 100644 --- a/src/js/ble_characteristic.js +++ b/src/js/ble_characteristic.js @@ -39,10 +39,10 @@ var util = require('util'); var debug = console.log; // require('debug')('ble_characteristic'); -var UuidUtil = require('ble_uuid_util'); +var uuidUtil = require('ble_uuid_util'); function Characteristic(options) { - this.uuid = UuidUtil.removeDashes(options.uuid); + this.uuid = uuidUtil.removeDashes(options.uuid); this.properties = options.properties || []; this.secure = options.secure || []; this.value = options.value || null; diff --git a/src/js/ble_descriptor.js b/src/js/ble_descriptor.js index 660756fdcf..c3e384d803 100644 --- a/src/js/ble_descriptor.js +++ b/src/js/ble_descriptor.js @@ -36,10 +36,10 @@ var debug = console.log; // require('debug')('descriptor'); -var UuidUtil = require('ble_uuid_util'); +var uuidUtil = require('ble_uuid_util'); function Descriptor(options) { - this.uuid = UuidUtil.removeDashes(options.uuid); + this.uuid = uuidUtil.removeDashes(options.uuid); this.value = options.value || new Buffer(0); } diff --git a/src/js/ble_hci_socket.js b/src/js/ble_hci_socket.js index 944ff7c37c..ba015958b6 100644 --- a/src/js/ble_hci_socket.js +++ b/src/js/ble_hci_socket.js @@ -36,9 +36,7 @@ var events = require('events'); -var BluetoothHciSocket= process.binding(process.binding.blehcisocket); - -inherits(BluetoothHciSocket, events.EventEmitter); +inherits(native /* BluetoothHciSocket */, events.EventEmitter); // extend prototype function inherits(target, source) { @@ -47,4 +45,4 @@ function inherits(target, source) { } } -module.exports = BluetoothHciSocket; +module.exports = native; /* BluetoothHciSocket */ diff --git a/src/js/ble_hci_socket_gap.js b/src/js/ble_hci_socket_gap.js index 4e766e007c..a8bca3803b 100644 --- a/src/js/ble_hci_socket_gap.js +++ b/src/js/ble_hci_socket_gap.js @@ -40,6 +40,7 @@ var events = require('events'); var util = require('util'); var Hci = require('ble_hci_socket_hci'); +var uuidUtil = require('ble_uuid_util'); var isLinux = (process.platform === 'linux'); var isIntelEdison = false; // isLinux && (os.release().indexOf('edison') !== -1); @@ -76,7 +77,7 @@ Gap.prototype.startAdvertising = function(name, serviceUuids) { if (serviceUuids && serviceUuids.length) { for (i = 0; i < serviceUuids.length; i++) { - var serviceUuid = new Buffer(serviceUuids[i].match(/.{1,2}/g).reverse().join(''), 'hex'); + var serviceUuid = new Buffer(uuidUtil.reverseByteOrder(serviceUuids[i], ''), 'hex'); if (serviceUuid.length === 2) { serviceUuids16bit.push(serviceUuid); diff --git a/src/js/ble_hci_socket_gatt.js b/src/js/ble_hci_socket_gatt.js index 13f65866a4..5430b2b627 100644 --- a/src/js/ble_hci_socket_gatt.js +++ b/src/js/ble_hci_socket_gatt.js @@ -40,6 +40,7 @@ var debug = console.log; // require('debug')('ble_hci_socket_gatt'); var events = require('events'); var util = require('util'); +var uuidUtil = require('ble_uuid_util'); var ATT_OP_ERROR = 0x01; var ATT_OP_MTU_REQ = 0x02; @@ -479,7 +480,7 @@ Gatt.prototype.handleFindInfoRequest = function(request) { response.writeUInt16LE(info.handle, 2 + i * lengthPerInfo); - uuid = new Buffer(info.uuid.match(/.{1,2}/g).reverse().join(''), 'hex'); + uuid = new Buffer(uuidUtil.reverseByteOrder(info.uuid, ''), 'hex'); for (var j = 0; j < uuid.length; j++) { //response[2 + i * lengthPerInfo + 2 + j] = uuid[j]; response.writeUInt8(uuid[j], 2 + i * lengthPerInfo + 2 + j); @@ -497,8 +498,8 @@ Gatt.prototype.handleFindByTypeRequest = function(request) { var startHandle = request.readUInt16LE(1); var endHandle = request.readUInt16LE(3); - var uuid = request.slice(5, 7).toString('hex').match(/.{1,2}/g).reverse().join(''); - var value = request.slice(7).toString('hex').match(/.{1,2}/g).reverse().join(''); + var uuid = uuidUtil.reverseByteOrder(request.slice(5, 7).toString('hex'), ''); + var value = uuidUtil.reverseByteOrder(request.slice(7).toString('hex'), ''); var handles = []; var handle; @@ -548,7 +549,7 @@ Gatt.prototype.handleReadByGroupRequest = function(request) { var startHandle = request.readUInt16LE(1); var endHandle = request.readUInt16LE(3); - var uuid = request.slice(5).toString('hex').match(/.{1,2}/g).reverse().join(''); + var uuid = uuidUtil.reverseByteOrder(request.slice(5).toString('hex'), ''); debug('read by group: startHandle = 0x' + startHandle.toString(16) + ', endHandle = 0x' + endHandle.toString(16) + ', uuid = 0x' + uuid.toString(16)); @@ -597,7 +598,7 @@ Gatt.prototype.handleReadByGroupRequest = function(request) { response.writeUInt16LE(service.startHandle, 2 + i * lengthPerService); response.writeUInt16LE(service.endHandle, 2 + i * lengthPerService + 2); - var serviceUuid = new Buffer(service.uuid.match(/.{1,2}/g).reverse().join(''), 'hex'); + var serviceUuid = new Buffer(uuidUtil.reverseByteOrder(service.uuid, ''), 'hex'); for (var j = 0; j < serviceUuid.length; j++) { //response[2 + i * lengthPerService + 4 + j] = serviceUuid[j]; response.writeUInt8(serviceUuid.readUInt8(j), 2 + i * lengthPerService + 4 + j); @@ -618,7 +619,7 @@ Gatt.prototype.handleReadByTypeRequest = function(request) { var startHandle = request.readUInt16LE(1); var endHandle = request.readUInt16LE(3); - var uuid = request.slice(5).toString('hex').match(/.{1,2}/g).reverse().join(''); + var uuid = uuidUtil.reverseByteOrder(request.slice(5).toString('hex'), ''); var i; var handle; @@ -668,7 +669,7 @@ Gatt.prototype.handleReadByTypeRequest = function(request) { response.writeUInt8(characteristic.properties, 2 + i * lengthPerCharacteristic + 2); response.writeUInt16LE(characteristic.valueHandle, 2 + i * lengthPerCharacteristic + 3); - var characteristicUuid = new Buffer(characteristic.uuid.match(/.{1,2}/g).reverse().join(''), 'hex'); + var characteristicUuid = new Buffer(uuidUtil.reverseByteOrder(characteristic.uuid, ''), 'hex'); for (var j = 0; j < characteristicUuid.length; j++) { //response[2 + i * lengthPerCharacteristic + 5 + j] = characteristicUuid[j]; response.writeUInt8(characteristicUuid.readUInt8(j), 2 + i * lengthPerCharacteristic + 5 + j); @@ -789,9 +790,9 @@ Gatt.prototype.handleReadOrReadBlobRequest = function(request) { if (handleType === 'service' || handleType === 'includedService') { result = ATT_ECODE_SUCCESS; - data = new Buffer(handle.uuid.match(/.{1,2}/g).reverse().join(''), 'hex'); + data = new Buffer(uuidUtil.reverseByteOrder(handle.uuid, ''), 'hex'); } else if (handleType === 'characteristic') { - var uuid = new Buffer(handle.uuid.match(/.{1,2}/g).reverse().join(''), 'hex'); + var uuid = new Buffer(uuidUtil.reverseByteOrder(handle.uuid, ''), 'hex'); result = ATT_ECODE_SUCCESS; data = new Buffer(3 + uuid.length); diff --git a/src/js/ble_hci_socket_hci.js b/src/js/ble_hci_socket_hci.js index 2428083c3b..cbb82bb2ea 100644 --- a/src/js/ble_hci_socket_hci.js +++ b/src/js/ble_hci_socket_hci.js @@ -38,6 +38,7 @@ var debug = console.log; // require('debug')('ble_hci'); var events = require('events'); var util = require('util'); +var uuidUtil = require('ble_uuid_util'); var BluetoothHciSocket = require('ble_hci_socket'); @@ -297,7 +298,7 @@ Hci.prototype.setAdvertisingParameters = function() { // length cmd.writeUInt8(15, 3); - var advertisementInterval = Math.floor((process.env.BLENO_ADVERTISING_INTERVAL ? parseInt(process.env.BLENO_ADVERTISING_INTERVAL) : 100) * 1.6); + var advertisementInterval = Math.floor((process.env.BLENO_ADVERTISING_INTERVAL ? parseInt(process.env.BLENO_ADVERTISING_INTERVAL) : 100) * '1.6'); // data cmd.writeUInt16LE(advertisementInterval, 4); // min interval @@ -562,7 +563,7 @@ Hci.prototype.processCmdCompleteEvent = function(cmd, status, result) { this.emit('readLocalVersion', hciVer, hciRev, lmpVer, manufacturer, lmpSubVer); } else if (cmd === READ_BD_ADDR_CMD) { this.addressType = 'public'; - this.address = result.toString('hex').match(/.{1,2}/g).reverse().join(':'); + this.address = uuidUtil.reverseByteOrder(result.toString('hex'), ':'); debug('address = ' + this.address); @@ -605,8 +606,8 @@ Hci.prototype.processLeConnComplete = function(status, data) { var handle = data.readUInt16LE(0); var role = data.readUInt8(2); var addressType = data.readUInt8(3) === 0x01 ? 'random': 'public'; - var address = data.slice(4, 10).toString('hex').match(/.{1,2}/g).reverse().join(':'); - var interval = data.readUInt16LE(10) * 1.25; + var address = uuidUtil.reverseByteOrder(data.slice(4, 10).toString('hex'), ':'); + var interval = (data.readUInt16LE(10) * 5) >> 2; var latency = data.readUInt16LE(12); // TODO: multiplier? var supervisionTimeout = data.readUInt16LE(14) * 10; var masterClockAccuracy = data.readUInt8(16); // TODO: multiplier? @@ -625,7 +626,7 @@ Hci.prototype.processLeConnComplete = function(status, data) { Hci.prototype.processLeConnUpdateComplete = function(status, data) { var handle = data.readUInt16LE(0); - var interval = data.readUInt16LE(2) * 1.25; + var interval = (data.readUInt16LE(2) * 5) >> 2; var latency = data.readUInt16LE(4); // TODO: multiplier? var supervisionTimeout = data.readUInt16LE(6) * 10; diff --git a/src/js/ble_hci_socket_hci_status.js b/src/js/ble_hci_socket_hci_status.js index ef621d7fb7..46798ca4a7 100644 --- a/src/js/ble_hci_socket_hci_status.js +++ b/src/js/ble_hci_socket_hci_status.js @@ -34,7 +34,7 @@ * SOFTWARE. */ -[ +module.exports = [ "Success", "Unknown HCI Command", "Unknown Connection Identifier", @@ -100,4 +100,4 @@ "Connection Failed to be Established", "MAC Connection Failed", "Coarse Clock Adjustment Rejected but Will Try to Adjust Using Clock Dragging" -] +]; diff --git a/src/js/ble_primary_service.js b/src/js/ble_primary_service.js index b9673e5794..34821f3f6e 100644 --- a/src/js/ble_primary_service.js +++ b/src/js/ble_primary_service.js @@ -39,10 +39,10 @@ var util = require('util'); var debug = console.log; // require('debug')('ble_primary_service'); -var UuidUtil = require('ble_uuid_util'); +var uuidUtil = require('ble_uuid_util'); function PrimaryService(options) { - this.uuid = UuidUtil.removeDashes(options.uuid); + this.uuid = uuidUtil.removeDashes(options.uuid); this.characteristics = options.characteristics || []; } diff --git a/src/js/ble_uuid_util.js b/src/js/ble_uuid_util.js index c8ee3d39b8..74d2da0e64 100644 --- a/src/js/ble_uuid_util.js +++ b/src/js/ble_uuid_util.js @@ -36,8 +36,25 @@ module.exports.removeDashes = function(uuid) { if (uuid) { - uuid = uuid.replace(/-/g, ''); + uuid = uuid.split('-').join(''); } return uuid; }; + +module.exports.reverseByteOrder = function(str, joint) { + str = String(str); + var uuid = ''; + var len = str.length; + var i = 0; + + while (i < (len & ~0x1)) { + uuid = joint + str.slice(i, i + 2) + uuid; + i = i + 2; + } + + if (len & 0x1) uuid = str.slice(i, i + 1) + uuid; + else if (joint !== '') uuid = uuid.substring(1, uuid.length); + + return uuid; +} diff --git a/src/js/bridge.js b/src/js/bridge.js new file mode 100644 index 0000000000..81f6269d5b --- /dev/null +++ b/src/js/bridge.js @@ -0,0 +1,30 @@ +/* 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. + */ + +function Bridge(moduleName) { + this.moduleName = moduleName; +} + +Bridge.prototype.send = function(command, message, callback) { + native.send(this.moduleName, command, message, function(err, results) { + callback(err, results); + }); +}; + +Bridge.prototype.sendSync = function(command, message) { + return native.send(this.moduleName, command, message); +}; + +module.exports = Bridge; diff --git a/src/js/buffer.js b/src/js/buffer.js index aeb297d317..e90f815ff5 100644 --- a/src/js/buffer.js +++ b/src/js/buffer.js @@ -14,10 +14,6 @@ */ -var bufferBuiltin = process.binding(process.binding.buffer); -var util = require('util'); - - function checkInt(buffer, value, offset, ext, max, min) { if (value > max || value < min) throw new TypeError('value is out of bounds'); @@ -32,6 +28,18 @@ function checkOffset(offset, ext, length) { } +function getEncodingType(encoding) { + switch (encoding) { + case 'hex': + return 0; + case 'base64': + return 1; + default: + return -1; + } +} + + // Buffer constructor // [1] new Buffer(size) // [2] new Buffer(buffer) @@ -39,69 +47,81 @@ function checkOffset(offset, ext, length) { // [4] new Buffer(string, encoding) // [5] new Buffer(array) function Buffer(subject, encoding) { - if (!util.isBuffer(this)) { - return new Buffer(subject); + if (!Buffer.isBuffer(this)) { + return new Buffer(subject, encoding); } - if (util.isNumber(subject)) { + if (typeof subject === 'number') { this.length = subject > 0 ? subject >>> 0 : 0; - } else if (util.isString(subject)) { + } else if (typeof subject === 'string') { this.length = Buffer.byteLength(subject, encoding); - } else if (util.isBuffer(subject) || util.isArray(subject)) { + } else if (Buffer.isBuffer(subject) || Array.isArray(subject)) { this.length = subject.length; } else { throw new TypeError('Bad arguments: Buffer(string|number|Buffer|Array)'); } - this._builtin = new bufferBuiltin(this, this.length); + // 'native' is the buffer object created via the C API. + native(this, this.length); - if (util.isString(subject)) { - if (!util.isUndefined(encoding) && util.isString(encoding)) { - switch (encoding) { - case 'hex': - if (this._builtin.hexWrite(subject, 0, this.length) != this.length) { - throw new TypeError('Invalid hex string'); - } - break; - default: - this.write(subject); + if (typeof subject === 'string') { + if (typeof encoding === 'string') { + encoding = getEncodingType(encoding); + if (encoding != -1) { + native.writeDecode(this, encoding, subject, 0, this.length); + } else { + this.write(subject); } } else { this.write(subject); } - } else if (util.isBuffer(subject)) { + } else if (Buffer.isBuffer(subject)) { subject.copy(this); - } else if (util.isArray(subject)) { + } else if (Array.isArray(subject)) { for (var i = 0; i < this.length; ++i) { - this._builtin.writeUInt8(subject[i], i); + native.writeUInt8(this, subject[i], i); } } } -// Buffer.byteLength(string) +// Buffer.byteLength(string, encoding) Buffer.byteLength = function(str, encoding) { - var len = bufferBuiltin.byteLength(str); + var bytes = native.byteLength(str); - if (!util.isUndefined(encoding) && util.isString(encoding)) { + if (typeof encoding === 'string') { + /* Might be invalid for incorrectly encoded strings. */ switch (encoding) { case 'hex': - return len >>> 1; + return bytes >>> 1; + case 'base64': + var len = str.length; + + if (len >= 4 && str.charCodeAt(len - 1) === 0x3D) { + len--; + + if (str.charCodeAt(len - 2) === 0x3D) { + len--; + } + } + + return len; } } - return len; + return bytes; }; // Buffer.concat(list) Buffer.concat = function(list) { - if (!util.isArray(list)) { + if (!Array.isArray(list)) { throw new TypeError('Bad arguments: Buffer.concat([Buffer])'); } var length = 0; - for (var i = 0; i < list.length; ++i) { - if (!util.isBuffer(list[i])) { + var i; + for (i = 0; i < list.length; ++i) { + if (!Buffer.isBuffer(list[i])) { throw new TypeError('Bad arguments: Buffer.concat([Buffer])'); } length += list[i].length; @@ -109,7 +129,7 @@ Buffer.concat = function(list) { var buffer = new Buffer(length); var pos = 0; - for (var i = 0; i < list.length; ++i) { + for (i = 0; i < list.length; ++i) { list[i].copy(buffer, pos); pos += list[i].length; } @@ -119,28 +139,28 @@ Buffer.concat = function(list) { // Buffer.isBuffer(object) -Buffer.isBuffer = function(object) { - return util.isBuffer(object); +Buffer.isBuffer = function(arg) { + return arg instanceof Buffer; }; // buffer.equals(otherBuffer) Buffer.prototype.equals = function(otherBuffer) { - if (!util.isBuffer(otherBuffer)) { + if (!Buffer.isBuffer(otherBuffer)) { throw new TypeError('Bad arguments: buffer.equals(Buffer)'); } - return this._builtin.compare(otherBuffer) == 0; + return native.compare(this, otherBuffer) == 0; }; // buffer.compare(otherBuffer) Buffer.prototype.compare = function(otherBuffer) { - if (!util.isBuffer(otherBuffer)) { + if (!Buffer.isBuffer(otherBuffer)) { throw new TypeError('Bad arguments: buffer.compare(Buffer)'); } - return this._builtin.compare(otherBuffer); + return native.compare(this, otherBuffer); }; @@ -153,19 +173,19 @@ Buffer.prototype.compare = function(otherBuffer) { // * sourceStart - default to 0 // * sourceEnd - default to buffer.length Buffer.prototype.copy = function(target, targetStart, sourceStart, sourceEnd) { - if (!util.isBuffer(target)) { + if (!Buffer.isBuffer(target)) { throw new TypeError('Bad arguments: buff.copy(Buffer)'); } - targetStart = util.isUndefined(targetStart) ? 0 : ~~targetStart; - sourceStart = util.isUndefined(sourceStart) ? 0 : ~~sourceStart; - sourceEnd = util.isUndefined(sourceEnd) ? this.length : ~~ sourceEnd; + targetStart = targetStart === undefined ? 0 : ~~targetStart; + sourceStart = sourceStart === undefined ? 0 : ~~sourceStart; + sourceEnd = sourceEnd === undefined ? this.length : ~~ sourceEnd; if ((sourceEnd > sourceStart) && (targetStart < 0)) { throw new RangeError('Attempt to write outside buffer bounds'); } - return this._builtin.copy(target, targetStart, sourceStart, sourceEnd); + return native.copy(this, target, targetStart, sourceStart, sourceEnd); }; @@ -175,20 +195,27 @@ Buffer.prototype.copy = function(target, targetStart, sourceStart, sourceEnd) { // [3] buffer.write(string, offset, length) // * offset - default to 0 // * length - default to buffer.length - offset -Buffer.prototype.write = function(string, offset, length) { - if (!util.isString(string)) { +Buffer.prototype.write = function(string, offset, length, encoding) { + if (typeof string !== 'string') { throw new TypeError('Bad arguments: buff.write(string)'); } - offset = util.isUndefined(offset) ? 0 : ~~offset; + offset = offset === undefined ? 0 : ~~offset; if (string.length > 0 && (offset < 0 || offset >= this.length)) { throw new RangeError('Attempt to write outside buffer bounds'); } var remaining = this.length - offset; - length = util.isUndefined(length) ? remaining : ~~length; + length = length === undefined ? remaining : ~~length; - return this._builtin.write(string, offset, length); + if (typeof encoding === 'string') { + encoding = getEncodingType(encoding); + if (encoding != -1) { + return native.writeDecode(this, encoding, string, offset, length); + } + } + + return native.write(this, string, offset, length); }; @@ -199,28 +226,31 @@ Buffer.prototype.write = function(string, offset, length) { // * start - default to 0 // * end - default to buff.length Buffer.prototype.slice = function(start, end) { - start = util.isUndefined(start) ? 0 : ~~start; - end = util.isUndefined(end) ? this.length : ~~end; + start = start === undefined ? 0 : ~~start; + end = end === undefined ? this.length : ~~end; - return this._builtin.slice(start, end); + return native.slice(this, start, end); }; // buff.toString([encoding,[,start[, end]]]) // [1] buff.toString() -// [2] buff.toString(start) -// [3] buff.toString(start, end) -// [4] buff.toString('hex') +// [2] buff.toString(encoding) +// [3] buff.toString(encoding, start) +// [4] buff.toString(encoding, start, end) // * start - default to 0 // * end - default to buff.length -Buffer.prototype.toString = function(start, end) { - if (util.isString(start) && start === "hex" && util.isUndefined(end)) { - return this._builtin.toHexString(); +Buffer.prototype.toString = function(encoding, start, end) { + if (typeof encoding === 'string') { + encoding = getEncodingType(encoding); + } else { + encoding = -1; } - start = util.isUndefined(start) ? 0 : ~~start; - end = util.isUndefined(end) ? this.length : ~~end; - return this._builtin.toString(start, end); + start = start === undefined ? 0 : ~~start; + end = end === undefined ? this.length : ~~end; + + return native.toString(this, encoding, start, end); }; @@ -232,7 +262,7 @@ Buffer.prototype.writeUInt8 = function(value, offset, noAssert) { offset = offset >>> 0; if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0); - this._builtin.writeUInt8(value & 0xff, offset); + native.writeUInt8(this, value & 0xff, offset); return offset + 1; }; @@ -245,8 +275,8 @@ Buffer.prototype.writeUInt16LE = function(value, offset, noAssert) { offset = offset >>> 0; if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0); - this._builtin.writeUInt8(value & 0xff, offset); - this._builtin.writeUInt8((value >>> 8) & 0xff, offset + 1); + native.writeUInt8(this, value & 0xff, offset); + native.writeUInt8(this, (value >>> 8) & 0xff, offset + 1); return offset + 2; }; @@ -258,11 +288,11 @@ Buffer.prototype.writeUInt32LE = function(value, offset, noAssert) { value = +value; offset = offset >>> 0; if (!noAssert) - checkInt(this, value, offset, 4, 0xffffffff, 0); - this._builtin.writeUInt8((value >>> 24) & 0xff, offset + 3); - this._builtin.writeUInt8((value >>> 16) & 0xff, offset + 2); - this._builtin.writeUInt8((value >>> 8) & 0xff, offset + 1); - this._builtin.writeUInt8(value & 0xff, offset); + checkInt(this, value, offset, 4, -1 >>> 0, 0); + native.writeUInt8(this, (value >>> 24) & 0xff, offset + 3); + native.writeUInt8(this, (value >>> 16) & 0xff, offset + 2); + native.writeUInt8(this, (value >>> 8) & 0xff, offset + 1); + native.writeUInt8(this, value & 0xff, offset); return offset + 4; }; @@ -274,7 +304,7 @@ Buffer.prototype.readUInt8 = function(offset, noAssert) { offset = offset >>> 0; if (!noAssert) checkOffset(offset, 1, this.length); - return this._builtin.readUInt8(offset); + return native.readUInt8(this, offset); }; @@ -285,7 +315,7 @@ Buffer.prototype.readInt8 = function(offset, noAssert) { offset = offset >>> 0; if (!noAssert) checkOffset(offset, 1, this.length); - var val = this._builtin.readUInt8(offset); + var val = native.readUInt8(this, offset); return !(val & 0x80) ? val : (0xff - val + 1) * -1; }; @@ -297,22 +327,50 @@ Buffer.prototype.readUInt16LE = function(offset, noAssert) { offset = offset >>> 0; if (!noAssert) checkOffset(offset, 2, this.length); - return this._builtin.readUInt8(offset) | - (this._builtin.readUInt8(offset + 1) << 8); + return native.readUInt8(this, offset) | + (native.readUInt8(this, offset + 1) << 8); }; // buff.fill(value) Buffer.prototype.fill = function(value) { - if (util.isNumber(value)) { + if (typeof value === 'number') { value = value & 255; for (var i = 0; i < this.length; i++) { - this._builtin.writeUInt8(value, i); + native.writeUInt8(this, value, i); } } return this; }; +// Method: Buffer.from() +// Buffer.from(Array) +// Buffer.from(string,encoding) +// Buffer.from(Buffer) +// Buffer.from(ArrayBuffer) +function from(value, encoding, length) { + + var arrayBuffer = native.fromArrayBuffer(value, encoding, length); + + if (arrayBuffer) { + return arrayBuffer; + } + if (Buffer.isBuffer(value) || (typeof value) === 'string' + || Array.isArray(value)) { + return new Buffer(value, encoding); + } + throw new TypeError('First argument must be' + + 'a string, Buffer, ArrayBuffer, Array, or array-like object'); +} + + +/* Register the Buffer object back to the native C + * so the other side can get the prototype in a consistent + * and safe manner. + */ +native.Buffer = Buffer; + module.exports = Buffer; module.exports.Buffer = Buffer; +module.exports.from = from; diff --git a/src/js/console.js b/src/js/console.js index 3d1dfa1965..29496923cc 100644 --- a/src/js/console.js +++ b/src/js/console.js @@ -15,7 +15,6 @@ var util = require('util'); -var consoleBuiltin = process.binding(process.binding.console); function Console() { @@ -24,13 +23,13 @@ function Console() { Console.prototype.log = Console.prototype.info = function() { - consoleBuiltin.stdout(util.format.apply(this, arguments) + '\n'); + native.stdout(util.format.apply(this, arguments) + '\n'); }; Console.prototype.warn = Console.prototype.error = function() { - consoleBuiltin.stderr(util.format.apply(this, arguments) + '\n'); + native.stderr(util.format.apply(this, arguments) + '\n'); }; diff --git a/src/js/crypto.js b/src/js/crypto.js new file mode 100644 index 0000000000..81c7df5d57 --- /dev/null +++ b/src/js/crypto.js @@ -0,0 +1,137 @@ +/* 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 shaTypes = { + 'sha1': 4, + 'sha256': 6, +}; + +var hashes = ['sha1', 'sha256']; + +function Verify(signtype) { + if (!(this instanceof Verify)) { + return new Verify(signtype); + } + + signtype = signtype.toLowerCase(); + + if (hashes.indexOf(signtype) < 0) { + throw new Error('Unknown signing algorithm.' + + 'Please use crypto.getSignatures()'); + } + + Object.defineProperty(this, 'hashtype', { + // defaults to writable: false, configurable: false + value: signtype, + enumerable: true, + }); +} + +Verify.prototype.update = function(data) { + if (this.data) { + if (Buffer.isBuffer(data)) { + this.data = Buffer.concat([this.data, data]); + return; + } + + this.data = Buffer.concat([this.data, new Buffer(data)]); + return; + } + + if (Buffer.isBuffer(data)) { + this.data = data; + return; + } + + this.data = new Buffer(data); +}; + +Verify.prototype.verify = function(publicKey, signature) { + if (this.data) { + var type = shaTypes[this.hashtype]; + var hash = native.shaEncode(this.data, type); + return native.rsaVerify(type, hash, publicKey, signature); + } + + throw new Error('verify shouldn\'t be called on an empty Verify'); +}; + +function Hash(hashtype) { + if (!(this instanceof Hash)) { + return new Hash(hashtype); + } + + if (hashes.indexOf(hashtype) < 0) { + throw new Error('Unknown hashing algorithm. Please use crypto.getHashes()'); + } + Object.defineProperty(this, 'hashtype', { + value: hashtype, + writable: false, + enumerable: true, + }); +} + +Hash.prototype.update = function(data) { + if (this.data) { + if (Buffer.isBuffer(data)) { + this.data = Buffer.concat(this.data, data); + return; + } + + this.data = Buffer.concat([this.data, new Buffer(data)]); + return; + } + this.data = new Buffer(data); +}; + +Hash.prototype.digest = function(encoding) { + if (this._finished) { + throw new Error('Digest can not be called twice on the same Hash object'); + } + + var result; + var type = shaTypes[this.hashtype]; + result = native.shaEncode(this.data, type); + + if (encoding == 'base64') { + result = native.base64Encode(result); + } else if (encoding == 'hex') { + result = result.toString('hex'); + } + + Object.defineProperty(this, '_finished', { + value: true, + writable: false, + enumerable: false, + }); + + return result; +}; + +function getHashes() { + return hashes; +} + +function createHash(hashtype) { + return new Hash(hashtype); +} + +function createVerify(signtype) { + return new Verify(signtype); +} + +exports.createHash = createHash; +exports.getHashes = getHashes; +exports.createVerify = createVerify; diff --git a/src/js/dgram.js b/src/js/dgram.js index 8d9f0b4bcc..d30f245b45 100644 --- a/src/js/dgram.js +++ b/src/js/dgram.js @@ -15,8 +15,7 @@ var EventEmitter = require('events').EventEmitter; var util = require('util'); - -var UDP = process.binding(process.binding.udp); +var Udp = require('udp'); var BIND_STATE_UNBOUND = 0; var BIND_STATE_BINDING = 1; @@ -40,7 +39,7 @@ function lookup4(address, callback) { function newHandle(type) { if (type == 'udp4') { - var handle = new UDP(); + var handle = new Udp(); handle.lookup = lookup4; return handle; } @@ -103,8 +102,6 @@ Socket.prototype.bind = function(port, address, callback) { this._bindState = BIND_STATE_BINDING; - var address; - if (util.isFunction(port)) { callback = port; port = 0; @@ -139,7 +136,7 @@ Socket.prototype.bind = function(port, address, callback) { self._handle._reuseAddr = self._reuseAddr; - var err = self._handle.bind(ip, port | 0); + err = self._handle.bind(ip, port | 0); if (err) { var ex = util.exceptionWithHostPort(err, 'bind', ip, port); self.emit('error', ex); @@ -152,7 +149,7 @@ Socket.prototype.bind = function(port, address, callback) { }); return self; -} +}; // thin wrapper around `send`, here for compatibility with dgram_legacy.js @@ -242,11 +239,11 @@ Socket.prototype.send = function(buffer, offset, length, port, address, if (!util.isArray(buffer)) { if (util.isString(buffer)) { - list = [ new Buffer(buffer) ]; + list = [new Buffer(buffer)]; } else if (!util.isBuffer(buffer)) { throw new TypeError('First argument must be a buffer or a string'); } else { - list = [ buffer ]; + list = [buffer]; } } else if (!(list = fixBufferList(buffer))) { throw new TypeError('Buffer list arguments must be buffers or strings'); @@ -298,7 +295,7 @@ function doSend(ex, self, ip, list, address, port, callback) { var buf = Buffer.concat(list); - var err = self._handle.send(buf, port, ip, function (err, length) { + var err = self._handle.send(buf, port, ip, function(err, length) { if (err) { err = util.exceptionWithHostPort(err, 'send', address, port); } else { @@ -312,7 +309,7 @@ function doSend(ex, self, ip, list, address, port, callback) { if (err && callback) { // don't emit as error, dgram_legacy.js compatibility - var ex = exceptionWithHostPort(err, 'send', address, port); + ex = util.exceptionWithHostPort(err, 'send', address, port); process.nextTick(callback, ex); } } @@ -353,8 +350,18 @@ Socket.prototype.address = function() { }; +// These object represents the different config types that +// this._handle.configure can do. +// The order of these must match the order in the udp C module. +var configTypes = { + 'BROADCAST': 0, + 'TTL': 1, + 'MULTICASTTTL': 2, + 'MULTICASTLOOPBACK': 3, +}; + Socket.prototype.setBroadcast = function(arg) { - var err = this._handle.setBroadcast(arg ? 1 : 0); + var err = this._handle.configure(configTypes.BROADCAST, arg ? 1 : 0); if (err) { throw util.errnoException(err, 'setBroadcast'); } @@ -366,7 +373,7 @@ Socket.prototype.setTTL = function(arg) { throw new TypeError('Argument must be a number'); } - var err = this._handle.setTTL(arg); + var err = this._handle.configure(configTypes.TTL, arg); if (err) { throw util.errnoException(err, 'setTTL'); } @@ -380,7 +387,7 @@ Socket.prototype.setMulticastTTL = function(arg) { throw new TypeError('Argument must be a number'); } - var err = this._handle.setMulticastTTL(arg); + var err = this._handle.configure(configTypes.MULTICASTTTL, arg); if (err) { throw util.errnoException(err, 'setMulticastTTL'); } @@ -390,7 +397,8 @@ Socket.prototype.setMulticastTTL = function(arg) { Socket.prototype.setMulticastLoopback = function(arg) { - var err = this._handle.setMulticastLoopback(arg ? 1 : 0); + var err = this._handle.configure(configTypes.MULTICASTLOOPBACK, + arg ? 1 : 0); if (err) { throw util.errnoException(err, 'setMulticastLoopback'); } @@ -448,7 +456,7 @@ Socket.prototype._stopReceiving = function() { function onMessage(nread, handle, buf, rinfo) { var self = handle.owner; if (nread < 0) { - return self.emit('error', errnoException(nread, 'recvmsg')); + return self.emit('error', util.errnoException(nread, 'recvmsg')); } rinfo.size = buf.length; // compatibility diff --git a/src/js/dns.js b/src/js/dns.js index 1a49965936..8401696c93 100644 --- a/src/js/dns.js +++ b/src/js/dns.js @@ -14,20 +14,6 @@ */ var util = require('util'); -var dnsBuiltin = process.binding(process.binding.dns); - -function dnsException(err, syscall, hostname) { - var ex = new Error(syscall + ' ' + err + (hostname ? ' ' + hostname : '')); - // TODO(hanjoung.lee@samsung.com) err should be a string (currently a number) - ex.code = err; - ex.errno = err; - ex.syscall = syscall; - if (hostname) { - ex.hostname = hostname; - } - return ex; -} - exports.lookup = function lookup(hostname, options, callback) { var hints = 0; @@ -59,34 +45,18 @@ exports.lookup = function lookup(hostname, options, callback) { if (family !== 0 && family !== 4 && family !== 6) throw new TypeError('invalid argument: family must be 4 or 6'); - function getaddrinfo() { - var err = dnsBuiltin.getaddrinfo( - hostname, - family, - hints, - function(err, address, family) { - var errObj = null; - if (err) { - errObj = dnsException(err, 'getaddrinfo', hostname); - } - callback(errObj, address, family); - }); - if (err) { - callback(dnsException(err, 'getaddrinfo', hostname), address, family); - } - } - if (process.platform != 'nuttx' && process.platform != 'tizenrt') { - getaddrinfo(); + if (process.platform != 'nuttx') { + native.getaddrinfo(hostname, family, hints, callback); } else { - // dnsBuiltin.getaddrinfo is synchronous on these platforms. + // native.getaddrinfo is synchronous on these platforms. // needs to be wrapped into an asynchronous call. process.nextTick(function() { - getaddrinfo() + native.getaddrinfo(hostname, family, hints, callback); }); } }; // uv_getaddrinfo flags -exports.ADDRCONFIG = dnsBuiltin.AI_ADDRCONFIG; -exports.V4MAPPED = dnsBuiltin.AI_V4MAPPED; +exports.ADDRCONFIG = native.AI_ADDRCONFIG; +exports.V4MAPPED = native.AI_V4MAPPED; diff --git a/src/js/events.js b/src/js/events.js index 992e661910..f6868fbaa3 100644 --- a/src/js/events.js +++ b/src/js/events.js @@ -19,9 +19,10 @@ var util = require('util'); function EventEmitter() { this._events = {}; -}; +} -module.exports.EventEmitter = EventEmitter; +module.exports = EventEmitter; +EventEmitter.EventEmitter = EventEmitter; EventEmitter.prototype.emit = function(type) { @@ -35,7 +36,7 @@ EventEmitter.prototype.emit = function(type) { if (err instanceof Error) { throw err; } else { - throw Error("Uncaught 'error' event"); + throw Error('Uncaught \'error\' event'); } } diff --git a/src/js/fs.js b/src/js/fs.js index e568a09a93..6080b7a34a 100644 --- a/src/js/fs.js +++ b/src/js/fs.js @@ -17,46 +17,20 @@ var fs = exports; var constants = require('constants'); var util = require('util'); -var fsBuiltin = process.binding(process.binding.fs); - -fs.Stats = function(stat) { - this.dev = stat.dev; - this.mode = stat.mode; - this.nlink = stat.nlink; - this.uid = stat.uid; - this.gid = stat.gid; - this.rdev = stat.rdev; - this.blksize = stat.blksize; - this.ino = stat.ino; - this.size = stat.size; - this.blocks = stat.blocks; -}; - - -fs.Stats.prototype.isDirectory = function() { - return ((this.mode & constants.S_IFMT) === constants.S_IFDIR); -}; - - -fs.Stats.prototype.isFile = function() { - return ((this.mode & constants.S_IFMT) === constants.S_IFREG); -}; - - -fsBuiltin._createStat = function(stat) { - return new fs.Stats(stat); -}; - +var fsBuiltin = native; fs.exists = function(path, callback) { + if (!(util.isString(path)) && !(util.isBuffer(path))) { + throw new TypeError('Path should be a string or a buffer'); + } if (!path || !path.length) { - process.nextTick(function () { + process.nextTick(function() { if (callback) callback(false); }); return; } - var cb = function(err, stat) { + var cb = function(err/* , stat */) { if (callback) callback(err ? false : true); }; @@ -112,7 +86,7 @@ fs.closeSync = function(fd) { }; -fs.open = function(path, flags, mode, callback) { +fs.open = function(path, flags, mode/* , callback */) { fsBuiltin.open(checkArgString(path, 'path'), convertFlags(flags), convertMode(mode, 438), @@ -242,7 +216,7 @@ fs.readFile = function(path, callback) { fs.close(fd, function(err) { return callback(err, Buffer.concat(buffers)); }); - } + }; }; @@ -408,6 +382,166 @@ fs.readdirSync = function(path) { }; +try { + var stream = require('stream'); + var Readable = stream.Readable; + var Writable = stream.Writable; + + + var ReadStream = function(path, options) { + if (!(this instanceof ReadStream)) { + return new ReadStream(path, options); + } + + options = options || {}; + + Readable.call(this, {defaultEncoding: options.encoding || null}); + + this.bytesRead = 0; + this.path = path; + this._autoClose = util.isNullOrUndefined(options.autoClose) || + options.autoClose; + this._fd = options.fd; + this._buff = new Buffer(options.bufferSize || 4096); + + var self = this; + if (util.isNullOrUndefined(this._fd)) { + fs.open(this.path, options.flags || 'r', options.mode || 438, + function(err, _fd) { + if (err) { + throw err; + } + self._fd = _fd; + self.emit('open', self._fd); + self.doRead(); + }); + } + + this.once('open', function(/* _fd */) { + this.emit('ready'); + }); + + if (this._autoClose) { + this.on('end', function() { + closeFile(self); + }); + } + }; + + + util.inherits(ReadStream, Readable); + + + ReadStream.prototype.doRead = function() { + var self = this; + fs.read(this._fd, this._buff, 0, this._buff.length, null, + function(err, bytes_read/* , buffer*/) { + if (err) { + if (self._autoClose) { + closeFile(self); + } + throw err; + } + + self.bytesRead += bytes_read; + if (bytes_read === 0) { + // Reached end of file. + // null must be pushed so the 'end' event will be emitted. + self.push(null); + } else { + self.push(bytes_read == self._buff.length ? + self._buff : self._buff.slice(0, bytes_read)); + self.doRead(); + } + }); + }; + + + fs.createReadStream = function(path, options) { + return new ReadStream(path, options); + }; + + + var WriteStream = function(path, options) { + if (!(this instanceof WriteStream)) { + return new WriteStream(path, options); + } + + options = options || {}; + + Writable.call(this); + + this._fd = options._fd; + this._autoClose = util.isNullOrUndefined(options.autoClose) || + options.autoClose; + this.bytesWritten = 0; + + var self = this; + if (!this._fd) { + fs.open(path, options.flags || 'w', options.mode || 438, + function(err, _fd) { + if (err) { + throw err; + } + self._fd = _fd; + self.emit('open', self._fd); + }); + } + + this.once('open', function(/* _fd */) { + self.emit('ready'); + }); + + if (this._autoClose) { + this.on('finish', function() { + closeFile(self); + }); + } + + this._readyToWrite(); + }; + + + util.inherits(WriteStream, Writable); + + + WriteStream.prototype._write = function(chunk, callback, onwrite) { + var self = this; + fs.write(this._fd, chunk, 0, chunk.length, + function(err, bytes_written/* , buffer */) { + if (err) { + if (self._autoClose) { + closeFile(self); + } + throw err; + } + this.bytesWritten += bytes_written; + + if (callback) { + callback(); + } + onwrite(); + }); + }; + + + fs.createWriteStream = function(path, options) { + return new WriteStream(path, options); + }; + + + var closeFile = function(stream) { + fs.close(stream._fd, function(err) { + if (err) { + throw err; + } + stream.emit('close'); + }); + }; +} catch (e) { +} + + function convertFlags(flag) { var O_APPEND = constants.O_APPEND; var O_CREAT = constants.O_CREAT; diff --git a/src/js/gpio.js b/src/js/gpio.js index 98809118b2..3c1098e9dd 100644 --- a/src/js/gpio.js +++ b/src/js/gpio.js @@ -13,189 +13,20 @@ * limitations under the License. */ -var EventEmitter = require('events').EventEmitter; -var gpio = process.binding(process.binding.gpio); -var util = require('util'); - -var defaultConfiguration = { - direction: gpio.DIRECTION.OUT, - mode: gpio.MODE.NONE, - edge: gpio.EDGE.NONE -}; - - -function Gpio() { - if (!(this instanceof Gpio)) { - return new Gpio(); - } -} - -Gpio.prototype.open = function(configuration, callback) { - return gpioPinOpen(configuration, callback); -}; - -Gpio.prototype.DIRECTION = gpio.DIRECTION; - -Gpio.prototype.MODE = gpio.MODE; - -Gpio.prototype.EDGE = gpio.EDGE; - -function gpioPinOpen(configuration, callback) { - var _binding = null; - - function GpioPin(configuration, callback) { - var self = this; - - // validate pin - if (util.isObject(configuration)) { - if (!util.isNumber(configuration.pin)) { - throw new TypeError('Bad configuration - pin is mandatory and number'); - } - } else { - throw new TypeError('Bad arguments - configuration should be Object') - } - - // validate direction - if (!util.isUndefined(configuration.direction)) { - if (configuration.direction !== gpio.DIRECTION.IN && - configuration.direction !== gpio.DIRECTION.OUT) { - throw new TypeError( - 'Bad configuration - direction should be DIRECTION.IN or OUT'); - } - } else { - configuration.direction = defaultConfiguration.direction; - } - - // validate mode - var mode = configuration.mode; - if (process.platform === 'nuttx' && !util.isUndefined(mode)) { - if (configuration.direction === gpio.DIRECTION.IN) { - if (mode !== gpio.MODE.NONE && mode !== gpio.MODE.PULLUP && - mode !== gpio.MODE.PULLDOWN) { - throw new TypeError( - 'Bad configuration - mode should be MODE.NONE, PULLUP or PULLDOWN'); - } - } else if (configuration.direction === gpio.DIRECTION.OUT) { - if (mode !== gpio.MODE.NONE && mode !== gpio.MODE.FLOAT && - mode !== gpio.MODE.PUSHPULL && mode !== gpio.MODE.OPENDRAIN) { - throw new TypeError( - 'Bad configuration - ' + - 'mode should be MODE.NONE, FLOAT, PUSHPULL or OPENDRAIN'); - } - } - } else { - configuration.mode = defaultConfiguration.mode; - } - - // validate edge - var edge = configuration.edge; - if (!util.isUndefined(configuration.edge)) { - if (edge !== gpio.EDGE.NONE && edge !== gpio.EDGE.RISING && - edge !== gpio.EDGE.FALLING && edge !== gpio.EDGE.BOTH) { - throw new TypeError( - 'Bad configuration - ' + - 'edge should be EDGE.NONE, RISING, FALLING or BOTH'); - } - } else { - configuration.edge = defaultConfiguration.edge; - } - - EventEmitter.call(this); - - _binding = new gpio.Gpio(configuration, function(err) { - util.isFunction(callback) && callback.call(self, err); +var gpio = { + open: function(config, callback) { + var gpioPin = new native(config, function(err) { + callback(err, gpioPin); }); + return gpioPin; + }, + openSync: function(config) { + return new native(config); + }, + DIRECTION: native.DIRECTION, + EDGE: native.EDGE, + MODE: native.MODE, +}; - _binding.onChange = function() { - self.emit('change'); - }; - - process.on('exit', (function(self) { - return function() { - if (!util.isNull(_binding)) { - self.closeSync(); - } - }; - })(this)); - } - - util.inherits(GpioPin, EventEmitter); - - GpioPin.prototype.write = function(value, callback) { - var self = this; - - if (util.isNull(_binding)) { - throw new Error('GPIO pin is not opened'); - } - - if (!util.isNumber(value) && !util.isBoolean(value)) { - throw new TypeError('Bad arguments - value should be Boolean'); - } - - _binding.write(!!value, function(err) { - util.isFunction(callback) && callback.call(self, err); - }); - }; - - GpioPin.prototype.writeSync = function(value) { - if (util.isNull(_binding)) { - throw new Error('GPIO pin is not opened'); - } - - if (!util.isNumber(value) && !util.isBoolean(value)) { - throw new TypeError('Bad arguments - value should be Boolean'); - } - - _binding.write(!!value); - }; - - GpioPin.prototype.read = function(callback) { - var self = this; - - if (util.isNull(_binding)) { - throw new Error('GPIO pin is not opened'); - } - - _binding.read(function(err, value) { - util.isFunction(callback) && callback.call(self, err, value); - }); - }; - - GpioPin.prototype.readSync = function() { - if (util.isNull(_binding)) { - throw new Error('GPIO pin is not opened'); - } - - return _binding.read(); - }; - - GpioPin.prototype.close = function(callback) { - var self = this; - - if (util.isNull(_binding)) { - throw new Error('GPIO pin is not opened'); - } - - _binding.close(function(err) { - util.isFunction(callback) && callback.call(self, err); - }); - - _binding = null; - }; - - GpioPin.prototype.closeSync = function() { - if (util.isNull(_binding)) { - throw new Error('GPIO pin is not opened'); - } - - _binding.close(); - - _binding = null; - }; - - return new GpioPin(configuration, callback); -} - - -module.exports = Gpio; +module.exports = gpio; diff --git a/src/js/http.js b/src/js/http.js index 80905e4db7..1a9ababbe8 100644 --- a/src/js/http.js +++ b/src/js/http.js @@ -13,21 +13,47 @@ * limitations under the License. */ -var Server = require('http_server').Server; -var client = require('http_client'); -var HTTPParser = process.binding(process.binding.httpparser).HTTPParser; +var net = require('net'); +var ClientRequest = require('http_client').ClientRequest; +var IncomingMessage = require('http_incoming').IncomingMessage; +var HTTPParser = require('http_parser').HTTPParser; +var HTTPServer = require('http_server'); +var util = require('util'); - -var ClientRequest = exports.ClientRequest = client.ClientRequest; +exports.ClientRequest = ClientRequest; exports.request = function(options, cb) { - return new ClientRequest(options, cb); + // Create socket. + var socket = new net.Socket(); + options.port = options.port || 80; + + return new ClientRequest(options, cb, socket); +}; + +function Server(options, requestListener) { + if (!(this instanceof Server)) { + return new Server(options, requestListener); + } + + net.Server.call(this, {allowHalfOpen: true}, + HTTPServer.connectionListener); + + HTTPServer.initServer.call(this, options, requestListener); +} +util.inherits(Server, net.Server); + +Server.prototype.setTimeout = function(ms, cb) { + this.timeout = ms; + if (cb) { + this.on('timeout', cb); + } }; +exports.Server = Server; -exports.createServer = function(requestListener){ - return new Server(requestListener); +exports.createServer = function(options, requestListener) { + return new Server(options, requestListener); }; @@ -39,3 +65,6 @@ exports.get = function(options, cb) { req.end(); return req; }; + +exports.IncomingMessage = IncomingMessage; +exports.ServerResponse = HTTPServer.ServerResponse; diff --git a/src/js/http_client.js b/src/js/http_client.js index 23e6f24cfc..4d43747baf 100644 --- a/src/js/http_client.js +++ b/src/js/http_client.js @@ -14,72 +14,77 @@ */ var util = require('util'); -var net = require('net'); -var HTTPParser = process.binding(process.binding.httpparser).HTTPParser; -var IncomingMessage = require('http_incoming').IncomingMessage; var OutgoingMessage = require('http_outgoing').OutgoingMessage; -var Buffer = require('buffer'); var common = require('http_common'); +var HTTPParser = require('http_parser').HTTPParser; - -function ClientRequest(options, cb) { - var self = this; - OutgoingMessage.call(self); +function ClientRequest(options, cb, socket) { + OutgoingMessage.call(this); // get port, host and method. - var port = options.port = options.port || 80; - var host = options.host = options.hostname || options.host || '127.0.0.1'; var method = options.method || 'GET'; - - self.path = options.path || '/'; + var path = options.path || '/'; + options.host = options.hostname || options.host || '127.0.0.1'; // If `options` contains header information, save it. if (options.headers) { var keys = Object.keys(options.headers); for (var i = 0, l = keys.length; i < l; i++) { var key = keys[i]; - self.setHeader(key, options.headers[key]); + this.setHeader(key, options.headers[key]); } } - // Register response event handler. - if (cb) { - self.once('response', cb); + if (options.host && !this.getHeader('host')) { + var hostHeader = options.host; + if (this._port && +this._port !== 80) { + hostHeader += ':' + this._port; + } + this.setHeader('Host', hostHeader); } - // Create socket. - var conn = new net.Socket(); - - // connect server. - conn.connect(port, host); + // store first header line to be sent. + this._storeHeader(method + ' ' + path + ' HTTP/1.1\r\n'); - // setup connection information. - setupConnection(self, conn); + // Register response event handler. + if (cb) { + this.once('response', cb); + } - // store first header line to be sent. - var firstHeaderLine = method + ' ' + self.path + ' HTTP/1.1\r\n'; - self._storeHeader(firstHeaderLine); + this.socket = socket; + this.options = options; } util.inherits(ClientRequest, OutgoingMessage); exports.ClientRequest = ClientRequest; +ClientRequest.prototype.end = function(data, encoding, callback) { + var self = this; -function setupConnection(req, socket) { - var parser = common.createHTTPParser(); - parser.reinitialize(HTTPParser.RESPONSE); - req.socket = socket; - req.connection = socket; - parser.socket = socket; - parser.incoming = null; - parser._headers = []; - req.parser = parser; + // connect server. + this.socket.connect(this.options, function() { + self._connected = true; + OutgoingMessage.prototype.end.call(self, data, encoding, callback); + }); + + // setup connection information. + setupConnection(this); +}; +function setupConnection(req) { + var socket = req.socket; + var parser = common.createHTTPParser(HTTPParser.RESPONSE); socket.parser = parser; socket._httpMessage = req; + parser.socket = socket; + parser.incoming = null; + parser._headers = []; parser.onIncoming = parserOnIncomingClient; + + req.parser = parser; + socket.on('error', socketOnError); socket.on('data', socketOnData); socket.on('end', socketOnEnd); @@ -91,13 +96,36 @@ function setupConnection(req, socket) { }); } +function cleanUpSocket(socket) { + var parser = socket.parser; + var req = socket._httpMessage; + + if (parser) { + // unref all links to parser, make parser GCed + parser.finish(); + parser = null; + socket.parser = null; + req.parser = null; + } + + socket.destroy(); +} + +function emitError(socket, err) { + var req = socket._httpMessage; + + if (err) { + var host; + if ((host = req.getHeader('host'))) { + err.message += ': ' + host; + } + req.emit('error', err); + } +} function socketOnClose() { var socket = this; var req = socket._httpMessage; - var parser = socket.parser; - - socket.read(); req.emit('close'); @@ -109,36 +137,15 @@ function socketOnClose() { }); res.push(null); } - else if (!req.res) { - // socket closed before response starts. - var err = new Error('socket hang up'); - req.emit('error', err); - } - if (parser) { - // unref all links to parser, make parser GCed - parser.finish(); - parser = null; - socket.parser = null; - req.parser = null; - } + cleanUpSocket(this); } - -function socketOnError(er) { - var socket = this; - var parser = socket.parser; - - if (parser) { - // unref all links to parser, make parser GCed - parser.finish(); - parser = null; - socket.parser = null; - } - socket.destroy(); +function socketOnError(err) { + cleanUpSocket(this); + emitError(this, err); } - function socketOnData(d) { var socket = this; var req = this._httpMessage; @@ -146,39 +153,18 @@ function socketOnData(d) { var ret = parser.execute(d); if (ret instanceof Error) { - // unref all links to parser, make parser GCed - parser.finish(); - parser = null; - socket.parser = null; - req.parser = null; - - socket.destroy(); + cleanUpSocket(socket); req.emit('error', ret); } } - function socketOnEnd() { - var socket = this; - var req = this._httpMessage; - var parser = this.parser; - - if (parser) { - // unref all links to parser, make parser GCed - parser.finish(); - parser = null; - socket.parser = null; - req.parser = null; - } - - socket.destroy(); + cleanUpSocket(this); } - - // This is called by parserOnHeadersComplete after response header is parsed. // TODO: keepalive support -function parserOnIncomingClient(res, shouldKeepAlive) { +function parserOnIncomingClient(res/* , shouldKeepAlive */) { var socket = this.socket; var req = socket._httpMessage; @@ -196,7 +182,7 @@ function parserOnIncomingClient(res, shouldKeepAlive) { req.emit('response', res); // response to HEAD req has no body - var isHeadResponse = (req.method == 'HEAD'); + var isHeadResponse = (req.method == 'HEAD'); return isHeadResponse; @@ -212,20 +198,19 @@ var responseOnEnd = function() { } }; +ClientRequest.prototype.abort = function() { + this.emit('abort'); + if (this.socket) { + cleanUpSocket(this.socket); + } +}; ClientRequest.prototype.setTimeout = function(ms, cb) { var self = this; if (cb) self.once('timeout', cb); - var emitTimeout = function() { + setTimeout(function() { self.emit('timeout'); - }; - - // In IoT.js, socket is already assigned, - // thus, it is sufficient to trigger timeout on socket 'connect' event. - this.socket.once('connect', function() { - self.socket.setTimeout(ms, emitTimeout); - }); - + }, ms); }; diff --git a/src/js/http_common.js b/src/js/http_common.js index 480638ad66..e207865ef8 100644 --- a/src/js/http_common.js +++ b/src/js/http_common.js @@ -14,37 +14,31 @@ */ var util = require('util'); -var HTTPParser = process.binding(process.binding.httpparser).HTTPParser; var IncomingMessage = require('http_incoming').IncomingMessage; -var OutgoingMessage = require('http_outgoing').OutgoingMessage; +var HTTPParser = require('http_parser').HTTPParser; - - -var createHTTPParser = function() { - // REQUEST is the default type. - // For RESPONSE, use HTTPParser.reinitialize(HTTPParser.RESPONSE) - var parser = new HTTPParser(HTTPParser.REQUEST); +exports.createHTTPParser = function(type) { + var parser = new HTTPParser(type); // cb during http parsing from C side(http_parser) parser.OnHeaders = parserOnHeaders; parser.OnHeadersComplete = parserOnHeadersComplete; parser.OnBody = parserOnBody; parser.OnMessageComplete = parserOnMessageComplete; + parser._IncomingMessage = IncomingMessage; return parser; }; -exports.createHTTPParser = createHTTPParser; - - // This is called when parsing of incoming http msg done function parserOnMessageComplete() { var stream = this.incoming; - if (stream) { - stream.complete = true; - // no more data from incoming, stream will emit 'end' event - stream.push(null); + if (!stream) { + return; } + stream.complete = true; + // no more data from incoming, stream will emit 'end' event + stream.push(null); stream.socket.resume(); } @@ -56,7 +50,7 @@ function parserOnHeadersComplete(info) { if (!url) { url = this._url; - this.url = ""; + this.url = ''; } if (!headers) { @@ -65,8 +59,9 @@ function parserOnHeadersComplete(info) { } - this.incoming = new IncomingMessage(this.socket); + this.incoming = new this._IncomingMessage(this.socket); this.incoming.url = url; + this.incoming.httpVersion = info.http_major + '.' + info.http_minor; // add header fields of headers to incoming.headers this.incoming.addHeaders(headers); diff --git a/src/js/http_incoming.js b/src/js/http_incoming.js index 72249c1fac..b3dc5391f6 100644 --- a/src/js/http_incoming.js +++ b/src/js/http_incoming.js @@ -21,7 +21,6 @@ function IncomingMessage(socket) { stream.Readable.call(this); this.socket = socket; - this.connection = socket; this.readable = true; @@ -32,6 +31,7 @@ function IncomingMessage(socket) { // for request (server) this.url = ''; this.method = null; + this.httpVersion = ''; // for response (client) this.statusCode = null; diff --git a/src/js/http_outgoing.js b/src/js/http_outgoing.js index c0585a090d..8ffa696d77 100644 --- a/src/js/http_outgoing.js +++ b/src/js/http_outgoing.js @@ -19,7 +19,7 @@ var stream = require('stream'); function OutgoingMessage() { - stream.Stream.call(this); + stream.Writable.call(this); this.writable = true; @@ -27,9 +27,12 @@ function OutgoingMessage() { this.finished = false; this._sentHeader = false; + this._connected = false; + + // storage for chunks when there is no connection established + this._chunks = []; this.socket = null; - this.connection = null; // response header string : same 'content' as this._headers this._header = null; // response header obj : (key, value) pairs @@ -37,7 +40,7 @@ function OutgoingMessage() { } -util.inherits(OutgoingMessage, stream.Stream); +util.inherits(OutgoingMessage, stream.Writable); exports.OutgoingMessage = OutgoingMessage; @@ -85,34 +88,37 @@ OutgoingMessage.prototype.end = function(data, encoding, callback) { this.finished = true; - this._finish(); + this.emit('prefinish'); return true; }; -OutgoingMessage.prototype._finish = function() { - this.emit('prefinish'); -}; - - // This sends chunk directly into socket -// TODO: buffering of chunk in the case of socket is not available OutgoingMessage.prototype._send = function(chunk, encoding, callback) { if (util.isFunction(encoding)) { callback = encoding; } - if (util.isBuffer(chunk)) { - chunk = chunk.toString(); - } - if (!this._sentHeader) { - chunk = this._header + "\r\n" + chunk; + this._chunks.push(this._header + '\r\n'); this._sentHeader = true; } - return this.connection.write(chunk, encoding, callback); + if (!this._connected) { + this._chunks.push(chunk); + return false; + } else { + while (this._chunks.length) { + this.socket.write(this._chunks.shift(), encoding, callback); + } + } + + if (this.socket) { + return this.socket.write(chunk, encoding, callback); + } + + return false; }; @@ -125,10 +131,7 @@ OutgoingMessage.prototype.write = function(chunk, encoding, callback) { return true; } - var ret = this._send(chunk, encoding, callback); - - return ret; - + return this._send(chunk, encoding, callback); }; @@ -141,7 +144,7 @@ OutgoingMessage.prototype._storeHeader = function(statusLine) { keys = Object.keys(this._headers); for (var i=0; i - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the author nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - /* Copyright 2016-present Samsung Electronics Co., Ltd. and other contributors * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -39,95 +13,16 @@ * limitations under the License. */ -/* This file includes all APIs in 'node-i2c'(https://github.com/kelly/node-i2c). - * Some functions are translated from coffee script(i2c.coffee) in 'node-i2c'. - */ - -var util = require('util'); -var i2c = process.binding(process.binding.i2c); - -function I2C() { - if (!(this instanceof I2C)) { - return new I2C(); - } -} - -I2C.prototype.open = function(configurable, callback) { - return i2cBusOpen(configurable, callback); -}; - - -function i2cBusOpen(configurable, callback) { - var _binding = null; - - function I2CBus(configurable, callback) { - if (util.isObject(configurable)) { - if (process.platform === 'linux') { - if (!util.isString(configurable.device)) { - throw new TypeError('Bad configurable - device: String'); - } - } else if (process.platform === 'nuttx') { - if (!util.isNumber(configurable.device)) { - throw new TypeError('Bad configurable - device: Number'); - } - } - - if (!util.isNumber(configurable.address)) { - throw new TypeError('Bad configurable - address: Number'); - } - - this.address = configurable.address; - - _binding = new i2c(configurable.device, (function(_this) { - return function(err) { - if (!err) { - _this.setAddress(configurable.address); - } - util.isFunction(callback) && callback(err); - }; - })(this)); - } - } - - I2CBus.prototype.close = function() { - _binding.close(); - }; - - I2CBus.prototype.setAddress = function(address, callback) { - if (!util.isNumber(address)) { - throw new TypeError('Bad argument - address: Number'); - } - - this.address = address; - _binding.setAddress(this.address); - - util.isFunction(callback) && callback(); - }; - - I2CBus.prototype.write = function(array, callback) { - if (!util.isArray(array)) { - throw new TypeError('Bad argument - array: Array'); - } - - this.setAddress(this.address); - _binding.write(array, function(err) { - util.isFunction(callback) && callback(err); +var i2c = { + open: function(config, callback) { + var i2cBus = new native(config, function(err) { + callback(err, i2cBus); }); - }; - - I2CBus.prototype.read = function(length, callback) { - if (!util.isNumber(length)) { - throw new TypeError('Bad argument - length: Number'); - } - - this.setAddress(this.address); - _binding.read(length, function(err, data) { - util.isFunction(callback) && callback(err, data); - }); - }; - - return new I2CBus(configurable, callback); -} - + return i2cBus; + }, + openSync: function(config) { + return new native(config); + }, +}; -module.exports = I2C; +module.exports = i2c; diff --git a/src/js/iotjs.js b/src/js/iotjs.js index 1a8915615f..e155e49c44 100644 --- a/src/js/iotjs.js +++ b/src/js/iotjs.js @@ -13,156 +13,169 @@ * limitations under the License. */ -this.global = this; - -function Native(id) { - this.id = id; - this.filename = id + '.js'; - this.exports = {}; -} +(function() { + this.global = this; + function Module(id) { + this.id = id; + this.exports = {}; + } -Native.cache = {}; + Module.cache = {}; + Module.builtin_modules = {}; + mixin(Module.builtin_modules, process.builtin_modules); + mixin(Module, process._private); + process._private = undefined; -Native.require = function(id) { - if (id == 'native') { - return Native; - } + Module.require = function(id) { + if (id === 'builtin') { + return Module; + } - if (Native.cache[id]) { - return Native.cache[id].exports; - } + if (Module.cache[id]) { + return Module.cache[id].exports; + } - var nativeMod = new Native(id); + var module = new Module(id); - Native.cache[id] = nativeMod; - nativeMod.compile(); + Module.cache[id] = module; + module.compile(); - return nativeMod.exports; -} + return module.exports; + }; -Native.prototype.compile = function() { - // process.native_sources has a list of pointers to - // the source strings defined in 'iotjs_js.h', not - // source strings. + Module.prototype.compile = function() { + Module.compileModule(this, Module.require); + }; - var fn = process.compileNativePtr(this.id); - fn(this.exports, Native.require, this); -} -global.console = Native.require('console'); -global.Buffer = Native.require('buffer'); + global.console = Module.require('console'); + global.Buffer = Module.require('buffer'); -(function() { var timers = undefined; var _timeoutHandler = function(mode) { if (timers == undefined) { - timers = Native.require('timers'); + timers = Module.require('timers'); } return timers[mode].apply(this, Array.prototype.slice.call(arguments, 1)); - } + }; global.setTimeout = _timeoutHandler.bind(this, 'setTimeout'); + global.setImmediate = _timeoutHandler.bind(this, 'setImmediate'); global.setInterval = _timeoutHandler.bind(this, 'setInterval'); global.clearTimeout = _timeoutHandler.bind(this, 'clearTimeout'); global.clearInterval = _timeoutHandler.bind(this, 'clearInterval'); -})(); -var EventEmitter = Native.require('events').EventEmitter; + var EventEmitter = Module.require('events').EventEmitter; + + EventEmitter.call(process); -EventEmitter.call(process); + mixin(process, EventEmitter.prototype); -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]; + function mixin(target, source) { + for (var prop in source) { + if (source.hasOwnProperty(prop) && !target[prop]) { + target[prop] = source[prop]; + } + } } -} -var nextTickQueue = []; + var nextTickQueue = []; -process.nextTick = nextTick; -process._onNextTick = _onNextTick; + process.nextTick = nextTick; + process._onNextTick = _onNextTick; -function _onNextTick() { - // clone nextTickQueue to new array object, and calls function - // iterating the cloned array. This is because, - // during processing nextTick - // a callback could add another next tick callback using - // `process.nextTick()`, if we calls back iterating original - // `nextTickQueue` that could turn into infinite loop. + function _onNextTick() { + // clone nextTickQueue to new array object, and calls function + // iterating the cloned array. This is because, + // during processing nextTick + // a callback could add another next tick callback using + // `process.nextTick()`, if we calls back iterating original + // `nextTickQueue` that could turn into infinite loop. - var callbacks = nextTickQueue.slice(0); - nextTickQueue = []; + var callbacks = nextTickQueue.slice(0); + nextTickQueue = []; - var len = callbacks.length; - for (var i = 0; i < len; ++i) { - try { - callbacks[i](); - } catch (e) { - process._onUncaughtException(e); + var len = callbacks.length; + for (var i = 0; i < len; ++i) { + try { + callbacks[i](); + } catch (e) { + process._onUncaughtException(e); + } } + + return nextTickQueue.length > 0; } - return nextTickQueue.length > 0; -} + function nextTick(callback) { + var args = Array.prototype.slice.call(arguments); + args[0] = null; + nextTickQueue.push(Function.prototype.bind.apply(callback, args)); + } -function nextTick(callback) { - nextTickQueue.push(callback); -} + process._onUncaughtException = _onUncaughtException; + function _onUncaughtException(error) { + var event = 'uncaughtException'; + if (process._events[event] && process._events[event].length > 0) { + try { + // Emit uncaughtException event. + process.emit('uncaughtException', error); + } catch (e) { + // Even uncaughtException handler thrown, that could not be handled. + console.error('uncaughtException handler throws: ' + e); + process.exit(1); + } + } else { + // Exit if there are no handler for uncaught exception. + console.error(error); + if (Array.isArray(error.stack)) { + error.stack.forEach(function(line) { + console.log(' at ' + line); + }); + } -process._onUncaughtException = _onUncaughtException; -function _onUncaughtException(error) { - var event = 'uncaughtException'; - if (process._events[event] && process._events[event].length > 0) { - try { - // Emit uncaughtException event. - process.emit('uncaughtException', error); - } catch (e) { - // Even uncaughtException handler thrown, that could not be handled. - console.error('uncaughtException handler throws: ' + e); process.exit(1); } - } else { - // Exit if there are no handler for uncaught exception. - console.error('uncaughtException: ' + error); - process.exit(1); } -} -process.exitCode = 0; -process._exiting = false; -process.emitExit = function(code) { - if (!process._exiting) { - process._exiting = true; - if (code || code == 0) { - process.exitCode = code; + process.exitCode = 0; + process._exiting = false; + process.emitExit = function(code) { + code = code || process.exitCode; + if (typeof code !== 'number') { + code = 0; } - process.emit('exit', process.exitCode || 0); - } -} - - -process.exit = function(code) { - try { - process.emitExit(code); - } catch (e) { - process.exitCode = 1; - process._onUncaughtException(e); - } finally { - process.doExit(process.exitCode || 0); - } -} - + if (!process._exiting) { + process._exiting = true; + if (code || code == 0) { + process.exitCode = code; + } + process.emit('exit', process.exitCode); + } + }; + + + process.exit = function(code) { + if (!process._exiting) { + try { + process.emitExit(code); + } catch (e) { + process.exitCode = 1; + process._onUncaughtException(e); + } finally { + process.doExit(process.exitCode); + } + } + }; -var module = Native.require('module'); -module.runMain(); + var module = Module.require('module'); + module.runMain(); +})(); diff --git a/src/js/module.js b/src/js/module.js index 8f5f7a7cc8..f42eb973eb 100644 --- a/src/js/module.js +++ b/src/js/module.js @@ -14,44 +14,146 @@ */ -var Native = require('native'); -var fs = Native.require('fs'); +var Builtin = require('builtin'); +var fs = Builtin.require('fs'); +var dynamicloader; +try { + dynamicloader = Builtin.require('napi'); +} catch (e) { + // the 'dynamicloader' module is not enabled, nothing to do. +} + +function normalizePathString(path) { + // Assume all path separators are '/' + var input = path.split('/'); + var output = []; + while (input.length > 0) { + if (input[0] === '.' || (input[0] === '' && input.length > 1)) { + input.shift(); + continue; + } + if (input[0] === '..') { + input.shift(); + if (output.length > 0 && output[output.length - 1] !== '..') { + output.pop(); + } else { + throw new Error('Requested path is below root: ' + path); + } + continue; + } + output.push(input.shift()); + } + return output; +} + +var path; +if (process.platform === 'windows') { + /* In case of windows: + * replace all '\' characters to '/' for ease of use for now. + */ + path = { + unixPathReplacer: new RegExp('/', 'g'), + winPathReplacer: new RegExp('\\\\', 'g'), + pathSeparator: '\\', + toUnixPath: function(pathString) { + return pathString.replace(path.winPathReplacer, '/'); + }, + toWindowsPath: function(pathString) { + return pathString.replace(path.unixPathReplacer, '\\\\'); + }, + isDeviceRoot: function(pathString) { + if (pathString.charCodeAt(1) !== 0x3A /* ':' */) { + return false; + } + var drive = pathString.charCodeAt(0); + return (drive >= 0x61 /* a */ && drive <= 0x7A /* z */) + || (drive >= 0x41 /* A */ && drive <= 0x5A /* Z */); + }, + normalizePath: function(pathString) { + pathString = path.toUnixPath(pathString); + + var deviceRoot = ''; + if (!path.isDeviceRoot(pathString)) { + deviceRoot = path.cwd().substr(0, 2) + '/'; + } + + var pathElements = normalizePathString(pathString); + return deviceRoot + pathElements.join('/'); + }, + cwd: function() { + return path.toUnixPath(process.cwd()); + }, + }; +} else { + path = { + isDeviceRoot: function(pathString) { + return pathString.charCodeAt(0) === 0x2F; /* '/' */ + }, + normalizePath: function(path) { + var beginning = ''; + if (path.indexOf('/') === 0) { + beginning = '/'; + } + + var pathElements = normalizePathString(path); + return beginning + pathElements.join('/'); + }, + cwd: process.cwd, + }; +} -function iotjs_module_t(id, parent) { +function Module(id, parent) { this.id = id; this.exports = {}; this.filename = null; this.parent = parent; -}; +} -module.exports = iotjs_module_t; +module.exports = Module; -iotjs_module_t.cache = {}; -iotjs_module_t.wrapper = Native.wrapper; -iotjs_module_t.wrap = Native.wrap; +Module.cache = {}; +// Cache to store not yet compiled remote modules +Module.remoteCache = {}; +var moduledirs = ['']; var cwd; -try { cwd = process.cwd(); } catch (e) { } +try { + cwd = process.env.IOTJS_WORKING_DIR_PATH || path.cwd(); +} catch (e) { } +if (cwd) { + moduledirs.push(cwd + '/'); + moduledirs.push(cwd + '/iotjs_modules/'); +} -var moduledirs = [""] -if(cwd){ - moduledirs.push(cwd + "/"); - moduledirs.push(cwd + "/iotjs_modules/"); +if (process.env.HOME) { + moduledirs.push(process.env.HOME + '/iotjs_modules/'); } -if(process.env.HOME){ - moduledirs.push(process.env.HOME + "/iotjs_modules/"); + +if (process.env.IOTJS_PATH) { + moduledirs.push(process.env.IOTJS_PATH + '/iotjs_modules/'); } -if(process.env.IOTJS_PATH){ - moduledirs.push(process.env.IOTJS_PATH + "/iotjs_modules/") + +if (process.env.IOTJS_EXTRA_MODULE_PATH) { + var extra_paths = process.env.IOTJS_EXTRA_MODULE_PATH.split(':'); + extra_paths.forEach(function(path) { + if (path.slice(-1) !== '/') { + path += '/'; + } + moduledirs.push(path); + }); } +function tryPath(modulePath, ext) { + return Module.tryPath(modulePath) || + Module.tryPath(modulePath + ext); +} -iotjs_module_t.resolveDirectories = function(id, parent) { +Module.resolveDirectories = function(id, parent) { var dirs = moduledirs; - if(parent) { - if(!parent.dirs){ + if (parent) { + if (!parent.dirs) { parent.dirs = []; } dirs = parent.dirs.concat(dirs); @@ -60,84 +162,101 @@ iotjs_module_t.resolveDirectories = function(id, parent) { }; -iotjs_module_t.resolveFilepath = function(id, directories) { - - for(var i = 0; i= 1) { + var type = (qos == 1) ? PacketTypeEnum.PUBACK : PacketTypeEnum.PUBREC; + + this.sendAck(type, packet_id); + } + + this.client.emit('message', data); +}; + +MQTTHandle.prototype.getPacketId = function() { + while (true) { + var packet_id = this.nextPacketId; + this.nextPacketId = (this.nextPacketId + 1) & 0xffff; + + if (!(packet_id in this.storage)) { + this.storage[packet_id] = { remainingTime: MQTTTimeout }; + this.storageCount++; + + return packet_id; + } + } +}; + +MQTTHandle.prototype.releasePacket = function(packet_id, error) { + // callback will be invalid after delete + var callback = this.storage[packet_id].callback; + + delete this.storage[packet_id]; + this.storageCount--; + + // This function should never fail. + try { + if (typeof callback == 'function') { + callback(error); + } else if (error) { + this.client.emit('error', error); + } + } catch (e) { + // Do nothing. + } +}; + +MQTTHandle.prototype.onpingresp = function() { + this.pingrespCounter = 0; +}; + +MQTTHandle.prototype.onack = function(packet_id, error) { + this.releasePacket(packet_id, error); +}; + +MQTTHandle.prototype.onpubrec = function(packet_id) { + /* + * Qos level 2 + * Handle PUBREC package. If this package is arrived, we have to send back + * a PUBREL package to the server. + */ + var buffer = native.sendAck(PacketTypeEnum.PUBREL, packet_id); + this.write(buffer); + + // Upodate packet rather than create a new one + var packet = this.storage[packet_id]; + packet.remainingTime = MQTTTimeout; + packet.packet = buffer; +}; + +MQTTHandle.prototype.onpubrel = function(data) { + /* + * Qos level 2 + * Handle PUBREL package. If this package is arrived, we have to send back + * a PUBCOMP package to the server. + */ + this.sendAck(PacketTypeEnum.PUBCOMP, data); +}; + +function MQTTClient(url, options, callback) { + if (!(this instanceof MQTTClient)) { + return new MQTTClient(url, options, callback); + } + + EventEmitter.call(this); + + var socket; + + if (typeof url == 'string') { + if (typeof options == 'function') { + callback = options; + options = {}; + } + } else { + if (typeof url == 'function') { + callback = url; + options = {}; + } else if (typeof options == 'function') { + callback = options; + options = url; + } else { + options = url; + } + + if (options.socket) { + socket = options.socket; + } else { + url = options.host || '127.0.0.1'; + } + } + + if (typeof callback == 'function') { + this.on('connect', callback); + } + + if (options.will) { + if (typeof options.topic == 'undefined' || + typeof options.message == 'undefined' || + options.qos < 0 || options.qos > 2) { + throw new Error('Incorrect mqtt will options'); + } + } + + var host = ''; + var create_tls = false; + + if (!socket) { + if (url.substring(0, 8) == 'mqtts://') { + create_tls = true; + host = url.substring(8); + } else if (url.substring(0, 7) == 'mqtt://') { + host = url.substring(7); + } else { + host = url; + } + } + + var keepalive = (options.keepalive || 60) | 0; + + if (keepalive < 30) { + keepalive = 30; + } + + if (keepalive > 65535) { + keepalive = 65535; + } + + options = Object.create(options, { + clientId: { value: options.clientId || defaultClientId() }, + host: { value: host }, + port: { value: options.port || 8883 }, + qos: { value: options.qos || 0 }, + keepalive: { value: keepalive }, + }); + + // Since network transmission takes time, the + // actual keepalive message is sent a bit earlier + this._handle = new MQTTHandle(this, keepalive - 5); + + var connectionMessage = native.connect(options); + + var onconnect = function() { + // Currently the connect message is tried only once. + // Multiple tries can be implemented later. + this.write(connectionMessage); + }; + + if (socket) { + onconnect.call(socket); + } else { + if (create_tls) { + if (!tls) { + tls = require('tls'); + } + + socket = tls.connect(options, onconnect); + } else { + if (!net) { + net = require('net'); + } + + socket = net.connect(options, onconnect); + } + } + + this._handle.socket = socket; + socket._mqttSocket = this; + + socket.on('error', onerror); + socket.on('data', ondata); + socket.on('finish', onfinish); +} +util.inherits(MQTTClient, EventEmitter); + +MQTTClient.prototype.end = function(force) { + var handle = this._handle; + + handle.isConnected = false; + + if (force || handle.storageCount == 0) { + handle.socket.end(native.disconnect()); + + // Abort ongoing messages. + clearInterval(this.timer); + this.storage = null; + this.storageCount = 0; + } +}; + +MQTTClient.prototype.checkConnection = function() { + if (!this._handle.isConnected) { + throw new Error('MQTT client is not connected'); + } +}; + +MQTTClient.prototype.publish = function(topic, message, options, callback) { + this.checkConnection(); + + var handle = this._handle; + + // header bits: | 16 bit packet id | 4 bit PUBLISH header | + var header = 0; + var qos = 0; + + if (options) { + if (options.retain) { + header = 0x1; + } + + qos = options.qos; + + if (qos !== 1 && qos !== 2) { + qos = 0; + } + + header |= (qos << 1); + } + + if (qos > 0) { + var packet_id = handle.getPacketId(); + header |= (packet_id << 4); + + var buffer = native.publish(topic, message, header); + handle.write(buffer); + + // Set dup flag. + buffer.writeUInt8(buffer.readUInt8(0) | 0x08, 0); + + var packet = handle.storage[packet_id]; + + packet.packet = buffer; + packet.callback = callback; + return; + } + + handle.write(native.publish(topic, message, header)); + + if (typeof callback == 'function') { + process.nextTick(callback); + } +}; + +MQTTClient.prototype.subscribe = function(topic, options, callback) { + this.checkConnection(); + + var handle = this._handle; + + var packet_id = handle.getPacketId(); + + // header bits: | 2 bit qos | 16 bit packet id | + var header = packet_id; + + var qos = 0; + + if (options) { + qos = options.qos; + + if (qos !== 1 || qos !== 2) { + qos = 0; + } + + header |= (qos << 16); + } + + var buffer = native.subscribe(topic, header); + + handle.write(buffer); + + var packet = handle.storage[packet_id]; + + packet.packet = buffer; + packet.callback = callback; +}; + +MQTTClient.prototype.unsubscribe = function(topic, callback) { + this.checkConnection(); + + var handle = this._handle; + + var packet_id = handle.getPacketId(); + + // header bits: | 16 bit packet id | + var header = packet_id; + + var buffer = native.unsubscribe(topic, header); + + handle.write(buffer); + + var packet = handle.storage[packet_id]; + + packet.packet = buffer; + packet.callback = callback; +}; + +function onerror(error) { + this._mqttSocket.emit('error', error); +} + +function ondata(data) { + native.MqttReceive(this._mqttSocket._handle, data); +} + +function onfinish() { + this._mqttSocket._handle.onEnd(); +} + +function storageTimerHit() { + // this: MQTTHandle + + // eslint-disable-next-line guard-for-in + for (var packet_id in this.storage) { + var packet = this.storage[packet_id]; + + packet.remainingTime--; + + if (packet.remainingTime <= 0) { + this.releasePacket(packet_id, new Error('Undelivered message')); + continue; + } + + // Every 8 seconds, the message is retransmitted. + if (!(packet.remainingTime & 0x7)) { + this.write(packet.packet); + } + } + + if (this.storageCount == 0 && !this.isConnected) { + // Graceful disconnect after all messages transmitted. + this.socket.end(native.disconnect()); + + clearInterval(this.timer); + this.storage = null; + return; + } + + if (this.pingrespCounter > 0) { + this.pingrespCounter--; + + if (this.pingrespCounter <= 0) { + this.onEnd(); + } + } + + this.keepaliveCounter++; + + if (this.keepaliveCounter >= this.keepalive) { + this.write(native.ping()); + + if (this.pingrespCounter == 0) { + this.pingrespCounter = (this.keepalive + 5) * 3 >> 1; + } + } +} + +/* + * Returns an unique client ID based on current time. + */ +function defaultClientId() { + return 'iotjs_mqtt_client_' + Date.now(); +} + +function connect(url, options, callback) { + return new MQTTClient(url, options, callback); +} + +exports.connect = connect; diff --git a/src/js/net.js b/src/js/net.js index 8cb3eef5a1..4be05a61df 100644 --- a/src/js/net.js +++ b/src/js/net.js @@ -18,13 +18,18 @@ var EventEmitter = require('events').EventEmitter; var stream = require('stream'); var util = require('util'); var assert = require('assert'); +var Tcp = require('tcp'); -var TCP = process.binding(process.binding.tcp); +function createTCP() { + var _tcp = new Tcp(); + return _tcp; +} +// Expected end message on nuttx platform. +var expectedEnding; -function createTCP() { - var tcp = new TCP(); - return tcp; +if (process.platform == 'nuttx') { + expectedEnding = new Buffer('\\e\\n\\d'); } @@ -39,6 +44,7 @@ function SocketState(options) { this.readable = true; this.destroyed = false; + this.errored = false; this.allowHalfOpen = options && options.allowHalfOpen || false; } @@ -49,7 +55,7 @@ function Socket(options) { return new Socket(options); } - if (util.isUndefined(options)) { + if (options === undefined) { options = {}; } @@ -104,7 +110,7 @@ Socket.prototype.connect = function() { var port = options.port; var dnsopts = { family: options.family >>> 0, - hints: 0 + hints: 0, }; if (!util.isNumber(port) || port < 0 || port > 65535) @@ -139,7 +145,6 @@ Socket.prototype.write = function(data, callback) { if (!util.isString(data) && !util.isBuffer(data)) { throw new TypeError('invalid argument'); } - return stream.Duplex.prototype.write.call(this, data, callback); }; @@ -150,16 +155,25 @@ Socket.prototype._write = function(chunk, callback, afterWrite) { var self = this; - resetSocketTimeout(self); - - self._handle.owner = self; - - self._handle.write(chunk, function(status) { - afterWrite(status); + if (self.errored) { + process.nextTick(afterWrite, 1); if (util.isFunction(callback)) { - callback.call(self, status); + process.nextTick(function(self, status) { + callback.call(self, status); + }, self, 1); } - }); + } else { + resetSocketTimeout(self); + + self._handle.owner = self; + + self._handle.write(chunk, function(status) { + afterWrite(status); + if (util.isFunction(callback)) { + callback.call(self, status); + } + }); + } }; @@ -216,7 +230,7 @@ Socket.prototype.destroySoon = function() { } else { self.once('finish', self.destroy); } -} +}; Socket.prototype.setKeepAlive = function(enable, delay) { @@ -235,7 +249,7 @@ Socket.prototype.address = function() { if (!this._sockname) { var out = {}; var err = this._handle.getsockname(out); - if (err) return {}; // FIXME(bnoordhuis) Throw? + if (err) return {}; // FIXME(bnoordhuis) Throw? this._sockname = out; } return this._sockname; @@ -279,14 +293,14 @@ function connect(socket, ip, port) { } else { socket.destroy(); emitError(socket, new Error('connect failed - status: ' + - TCP.errname(status))); + Tcp.errname(status))); } }; var err = socket._handle.connect(ip, port, afterConnect); if (err) { emitError(socket, new Error('connect failed - status: ' + - TCP.errname(err))); + Tcp.errname(err))); } } @@ -321,7 +335,7 @@ function resetSocketTimeout(socket) { clearSocketTimeout(socket); }, socket._timeout); } -}; +} function clearSocketTimeout(socket) { @@ -329,10 +343,15 @@ function clearSocketTimeout(socket) { clearTimeout(socket._timer); socket._timer = null; } -}; +} function emitError(socket, err) { + socket.errored = true; + stream.Duplex.prototype.end.call(socket, '', function() { + socket.destroy(); + }); + socket._readyToWrite(); socket.emit('error', err); } @@ -341,8 +360,8 @@ function maybeDestroy(socket) { var state = socket._socketState; if (!state.connecting && - !state.writable && - !state.readable) { + !state.writable && + !state.readable) { socket.destroy(); } } @@ -386,20 +405,25 @@ function onread(socket, nread, isEOF, buffer) { var err = new Error('read error: ' + nread); stream.Readable.prototype.error.call(socket, err); } else if (nread > 0) { - if (process.platform != 'nuttx') { + if (process.platform !== 'nuttx') { stream.Readable.prototype.push.call(socket, buffer); return; } - var str = buffer.toString(); + // We know for sure the last 6 characters are going to be the ending. + // Lets create a buffer with those 6 characters without toString conversion. + var eofLength = 6; + var bufferLength = buffer.length; + var eofNeeded = false; - if (str.length >= 6 - && str.substr(str.length - 6, str.length) == '\\e\\n\\d') { - eofNeeded = true; - buffer = buffer.slice(0, str.length - 6); + if (bufferLength >= eofLength && + expectedEnding.compare(buffer.slice(bufferLength - eofLength, + bufferLength)) == 0) { + eofNeeded = true; + buffer = buffer.slice(0, bufferLength - eofLength); } - if (str.length == 6 && eofNeeded) { + if (bufferLength == eofLength && eofNeeded) { // Socket.prototype.end with no argument } else { stream.Readable.prototype.push.call(socket, buffer); @@ -422,7 +446,7 @@ function onSocketFinish() { return self.destroy(); } else { // Readable stream alive, shutdown only outgoing stream. - var err = self._handle.shutdown(function() { + self._handle.shutdown(function() { if (self._readableState.ended) { self.destroy(); } @@ -443,7 +467,6 @@ function onSocketEnd() { } - function Server(options, connectionListener) { if (!(this instanceof Server)) { return new Server(options, connectionListener); @@ -511,7 +534,7 @@ Server.prototype.listen = function() { self._handle.createTCP = createTCP; self._handle.owner = self; - var err = self._handle.listen(backlog); + err = self._handle.listen(backlog); if (err) { self._handle.close(); @@ -583,14 +606,14 @@ function onconnection(status, clientHandle) { var server = this.owner; if (status) { - server.emit('error', new Error('accept error: ' + TCP.errname(status))); + server.emit('error', new Error('accept error: ' + Tcp.errname(status))); return; } // Create socket object for connecting client. var socket = new Socket({ handle: clientHandle, - allowHalfOpen: server.allowHalfOpen + allowHalfOpen: server.allowHalfOpen, }); socket._server = server; diff --git a/src/js/pwm.js b/src/js/pwm.js index da0c69642b..cf159ef1b4 100644 --- a/src/js/pwm.js +++ b/src/js/pwm.js @@ -13,229 +13,16 @@ * limitations under the License. */ -var util = require('util'); -var pwm = process.binding(process.binding.pwm); - - -function Pwm() { - if (!(this instanceof Pwm)) { - return new Pwm(); - } -} - -Pwm.prototype.open = function(configuration, callback) { - return pwmPinOpen(configuration, callback); -}; - - -function pwmPinOpen(configuration, callback) { - var _binding = null; - - function PwmPin(configuration, callback) { - var self = this; - self._configuration = {}; - - if (util.isObject(configuration)) { - if (process.platform === 'linux') { - if (util.isNumber(configuration.chip)) { - self._configuration.chip = configuration.chip - } else { - self._configuration.chip = 0; - } - } - - if (!util.isNumber(configuration.pin)) { - throw new TypeError( - 'Bad configuration - pin is mandatory and should be Number'); - } else { - self._configuration.pin = configuration.pin; - } - } else { - throw new TypeError('Bad arguments - configuration should be Object') - } - - // validate configuration - var dutyCycle = configuration.dutyCycle; - var period = configuration.period; - if (!util.isNumber(period) && util.isNumber(configuration.frequency)) { - period = 1.0 / configuration.frequency; - } - - if (util.isNumber(dutyCycle) && dutyCycle >= 0.0 && dutyCycle <= 1.0 && - util.isNumber(period) && util.isFinite(period) && period > 0) { - self._configuration.dutyCycle = dutyCycle; - self._configuration.period = period; - } - - _binding = new pwm(self._configuration, function(err) { - util.isFunction(callback) && callback.call(self, err); - }); - - process.on('exit', (function(self) { - return function() { - if (!util.isNull(_binding)) { - self.closeSync(); - } - }; - })(this)); - } - - PwmPin.prototype._validatePeriod = function(period) { - if (!util.isNumber(period)) { - throw new TypeError('Period is not a number(' + typeof(period) + ')'); - } else if (period < 0) { - throw new RangeError('Period(' + period + ') is negative'); - } - return true; - }; - - PwmPin.prototype._validateFrequency = function(frequency) { - if (!util.isNumber(frequency)) { - throw new TypeError('Frequency is not a number(' + - typeof(frequency) + ')'); - } else if (frequency <= 0) { - throw RangeError('Nonpositivie frequency of ' + frequency); - } - return true; - }; - - PwmPin.prototype._validateDutyCycle = function(dutyCycle) { - if (!util.isNumber(dutyCycle)) { - throw TypeError('DutyCycle is not a number(' + typeof(dutyCycle) + ')'); - } else if (dutyCycle < 0.0 || dutyCycle > 1.0) { - throw RangeError('DutyCycle of ' + dutyCycle + ' out of bounds [0..1]'); - } - return true; - }; - - PwmPin.prototype.setPeriod = function(period, callback) { - var self = this; - - if (util.isNull(_binding)) { - throw new Error('Pwm pin is not opened'); - } - - if (this._validatePeriod(period)) { - _binding.setPeriod(period, function(err) { - util.isFunction(callback) && callback.call(self, err); - }); - } - }; - - PwmPin.prototype.setPeriodSync = function(period) { - if (util.isNull(_binding)) { - throw new Error('Pwm pin is not opened'); - } - - if (this._validatePeriod(period)) { - _binding.setPeriod(period); - } - }; - - PwmPin.prototype.setFrequency = function(frequency, callback) { - var self = this; - - if (util.isNull(_binding)) { - throw new Error('Pwm pin is not opened'); - } - - if (this._validateFrequency(frequency)) { - _binding.setPeriod(1.0 / frequency, function(err) { - util.isFunction(callback) && callback.call(self, err); - }); - } - }; - - PwmPin.prototype.setFrequencySync = function(frequency) { - if (util.isNull(_binding)) { - throw new Error('Pwm pin is not opened'); - } - - if (this._validateFrequency(frequency)) { - _binding.setPeriod(1.0 / frequency); - } - }; - - PwmPin.prototype.setDutyCycle = function(dutyCycle, callback) { - var self = this; - - if (util.isNull(_binding)) { - throw new Error('Pwm pin is not opened'); - } - - // Check arguments. - if (this._validateDutyCycle(dutyCycle)) { - _binding.setDutyCycle(dutyCycle, function(err) { - util.isFunction(callback) && callback.call(self, err); - }); - } - }; - - PwmPin.prototype.setDutyCycleSync = function(dutyCycle) { - if (util.isNull(_binding)) { - throw new Error('Pwm pin is not opened'); - } - - // Check arguments. - if (this._validateDutyCycle(dutyCycle)) { - _binding.setDutyCycle(dutyCycle); - } - }; - - PwmPin.prototype.setEnable = function(enable, callback) { - var self = this; - - if (util.isNull(_binding)) { - throw new Error('Pwm pin is not opened'); - } - - // Check arguments. - if (!util.isNumber(enable) && !util.isBoolean(enable)) { - throw new TypeError('enable is of type ' + typeof(enable)); - } - - _binding.setEnable(!!enable, function(err) { - util.isFunction(callback) && callback.call(self, err); +var pwm = { + open: function(config, callback) { + var pwmPin = new native(config, function(err) { + callback(err, pwmPin); }); - }; - - PwmPin.prototype.setEnableSync = function(enable) { - if (util.isNull(_binding)) { - throw new Error('Pwm pin is not opened'); - } - - // Check arguments. - if (!util.isNumber(enable) && !util.isBoolean(enable)) { - throw new TypeError('enable is of type ' + typeof(enable)); - } - - _binding.setEnable(!!enable); - }; - - PwmPin.prototype.close = function(callback) { - var self = this; - - if (util.isNull(_binding)) { - throw new Error('Pwm pin is not opened'); - } - - _binding.close(function(err) { - util.isFunction(callback) && callback.call(self, err); - }); - _binding = null; - }; - - PwmPin.prototype.closeSync = function() { - if (util.isNull(_binding)) { - throw new Error('Pwm pin is not opened'); - } - - _binding.close(); - _binding = null; - }; - - return new PwmPin(configuration, callback); -} - + return pwmPin; + }, + openSync: function(config) { + return new native(config); + }, +}; -module.exports = Pwm; +module.exports = pwm; diff --git a/src/js/spi.js b/src/js/spi.js index 1e2ba4fca1..f7da851b7b 100644 --- a/src/js/spi.js +++ b/src/js/spi.js @@ -13,210 +13,19 @@ * limitations under the License. */ -var util = require('util'); -var spi = process.binding(process.binding.spi); - -var defaultConfiguration = { - mode : spi.MODE[0], - chipSelect : spi.CHIPSELECT.NONE, - maxSpeed : 500000, - bitsPerWord : 8, - bitOrder : spi.BITORDER.MSB, - loopback : false -}; - - -function Spi() { - if (!(this instanceof Spi)) { - return new Spi(); - } -} - -Spi.prototype.open = function(configuration, callback) { - return spiBusOpen(configuration, callback); -}; - -Spi.prototype.MODE = spi.MODE; -Spi.prototype.CHIPSELECT = spi.CHIPSELECT; -Spi.prototype.BITORDER = spi.BITORDER; - - -function spiBusOpen(configuration, callback) { - var _binding = null; - - function SpiBus(configuration, callback) { - var self = this; - - // validate device - if (util.isObject(configuration)) { - if (!util.isString(configuration.device)) { - throw new TypeError( - 'Bad configuration - device is mandatory and String'); - } - } else { - throw new TypeError('Bad arguments - configuration should be Object'); - } - - // validate mode - var mode = configuration.mode; - if (!util.isUndefined(mode)) { - if (mode !== spi.MODE[0] && mode !== spi.MODE[1] && - mode !== spi.MODE[2] && mode !== spi.MODE[3]) { - throw new TypeError( - 'Bad arguments - mode should be MODE[0], [1], [2] or [3]'); - } - } else { - configuration.mode = defaultConfiguration.mode; - } - - // validate chip-select - var chipSelect = configuration.chipSelect; - if (!util.isUndefined(chipSelect)) { - if (chipSelect != spi.CHIPSELECT.NONE && - chipSelect != spi.CHIPSELECT.HIGH) { - throw new TypeError( - 'Bad arguments - chipSelect should be CHIPSELECT.NONE or HIGH'); - } - } else { - configuration.chipSelect = defaultConfiguration.chipSelect; - } - - // validate max speed - if (!util.isUndefined(configuration.maxSpeed)) { - if (!util.isNumber(configuration.maxSpeed)) { - throw new TypeError('Bad arguments - maxSpeed should be Number'); - } - } else { - configuration.maxSpeed = defaultConfiguration.maxSpeed - } - - // validate bits per word - var bitsPerWord = configuration.bitsPerWord; - if (!util.isUndefined(bitsPerWord)) { - if (bitsPerWord != 8 && bitsPerWord != 9) { - throw new TypeError('Bad arguments - bitsPerWord should be 8 or 9'); - } - } else { - configuration.bitsPerWord = defaultConfiguration.bitsPerWord; - } - - // validate bit order - var bitOrder = configuration.bitOrder; - if (!util.isUndefined(bitOrder)) { - if (bitOrder != spi.BITORDER.MSB && bitOrder != spi.BITORDER.LSB) { - throw new TypeError( - 'Bad arguments - bitOrder should be BITORDER.MSB or LSB'); - } - } else { - configuration.bitOrder = defaultConfiguration.bitOrder; - } - - // validate loopback - var loopback = configuration.loopback; - if (!util.isUndefined(loopback)) { - if (!util.isBoolean(loopback)) { - throw new TypeError('Bad arguments - loopback should be Boolean'); - } - } else { - configuration.loopback = defaultConfiguration.loopback; - } - - _binding = new spi.Spi(configuration, function(err) { - util.isFunction(callback) && callback.call(self, err); - }); - - process.on('exit', (function(self) { - return function() { - if (!util.isNull(_binding)) { - self.closeSync(); - } - }; - })(this)); - } - - SpiBus.prototype.transfer = function(txBuffer, rxBuffer, callback) { - var self = this; - - if (util.isNull(_binding)) { - throw new Error('SPI bus is not opened'); - } - - if (util.isUndefined(txBuffer.length) || util.isUndefined(rxBuffer.length) - || txBuffer.length <= 0 || rxBuffer.length <= 0 - || txBuffer.length != rxBuffer.length) { - throw new Error('Bad arguments - buffer length'); - } - - var rxLength = rxBuffer.length; - var afterCallback = function(err, buffer) { - for (var i = 0; i < rxLength; i++) { - rxBuffer[i] = buffer[i]; - } - - util.isFunction(callback) && callback.call(self, err); - }; - - if (util.isArray(txBuffer) && util.isArray(rxBuffer)) { - _binding.transferArray(txBuffer, rxBuffer, afterCallback); - } else if (util.isBuffer(txBuffer) && util.isBuffer(rxBuffer)) { - _binding.transferBuffer(txBuffer, rxBuffer, afterCallback); - } else { - throw new TypeError('Bad arguments - buffer should be Array or Buffer'); - } - }; - - SpiBus.prototype.transferSync = function(txBuffer, rxBuffer) { - if (util.isNull(_binding)) { - throw new Error('SPI bus is not opened'); - } - - if (util.isUndefined(txBuffer.length) || util.isUndefined(rxBuffer.length) - || txBuffer.length <= 0 || rxBuffer.length <= 0 - || txBuffer.length != rxBuffer.length) { - throw new Error('Bad arguments - buffer length'); - } - - var data = null; - if (util.isArray(txBuffer) && util.isArray(rxBuffer)) { - data = _binding.transferArray(txBuffer, rxBuffer); - } else if (util.isBuffer(txBuffer) && util.isBuffer(rxBuffer)) { - data = _binding.transferBuffer(txBuffer, rxBuffer); - } else { - throw new TypeError('Bad arguments - buffer should be Array or Buffer'); - } - - if (data !== null && (util.isArray(data) || util.isBuffer(data)) && - data.length === rxBuffer.length) { - for (var i = 0; i < rxBuffer.length; i++) { - rxBuffer[i] = data[i]; - } - } else { - throw new Error('Spi Transfer Error'); - } - }; - - SpiBus.prototype.close = function(callback) { - var self = this; - - if (util.isNull(_binding)) { - throw new Error('SPI bus is not opened'); - } - - return _binding.close(function(err) { - util.isFunction(callback) && callback.call(self, err); +var spi = { + open: function(config, callback) { + var spiBus = new native(config, function(err) { + callback(err, spiBus); }); - }; - - SpiBus.prototype.closeSync = function() { - if (util.isNull(_binding)) { - throw new Error('SPI bus is not opened'); - } - - return _binding.close(); - }; - - return new SpiBus(configuration, callback); -} - + return spiBus; + }, + openSync: function(config) { + return new native(config); + }, + MODE: native.MODE, + CHIPSELECT: native.CHIPSELECT, + BITORDER: native.BITORDER, +}; -module.exports = Spi; +module.exports = spi; diff --git a/src/js/stream.js b/src/js/stream.js index bd31230845..5bf2a52318 100644 --- a/src/js/stream.js +++ b/src/js/stream.js @@ -14,17 +14,15 @@ */ -var eventEmitter = require('events').EventEmitter; +var StreamInternal = require('stream_internal'); var util = require('util'); function Stream() { - eventEmitter.call(this); -}; - - -util.inherits(Stream, eventEmitter); + StreamInternal.call(this); +} +util.inherits(Stream, StreamInternal); exports.Stream = Stream; diff --git a/src/js/stream_duplex.js b/src/js/stream_duplex.js index 7beb75cda1..a147a61535 100644 --- a/src/js/stream_duplex.js +++ b/src/js/stream_duplex.js @@ -25,6 +25,8 @@ function Duplex(options) { } Readable.call(this, options); + options = options || {}; + options._isDuplex = true; Writable.call(this, options); } diff --git a/src/js/stream_internal.js b/src/js/stream_internal.js new file mode 100644 index 0000000000..db3805cece --- /dev/null +++ b/src/js/stream_internal.js @@ -0,0 +1,27 @@ +/* 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 eventEmitter = require('events').EventEmitter; +var util = require('util'); + + +function Stream() { + eventEmitter.call(this); +} + +util.inherits(Stream, eventEmitter); + +module.exports = Stream; diff --git a/src/js/stream_readable.js b/src/js/stream_readable.js index 19112f5697..cf4465a6c6 100644 --- a/src/js/stream_readable.js +++ b/src/js/stream_readable.js @@ -14,9 +14,9 @@ */ -var Stream = require('stream').Stream; +var Stream = require('stream_internal'); +var Writable = require('stream_writable'); var util = require('util'); -var assert = require('assert'); function ReadableState(options) { @@ -38,7 +38,7 @@ function ReadableState(options) { // become `true` just before emit 'end' event. this.endEmitted = false; -}; +} function Readable(options) { @@ -49,7 +49,7 @@ function Readable(options) { this._readableState = new ReadableState(options); Stream.call(this); -}; +} util.inherits(Readable, Stream); @@ -70,10 +70,6 @@ Readable.prototype.read = function(n) { res = null; } - if (state.ended && state.length == 0) { - emitEnd(this); - } - return res; }; @@ -106,9 +102,7 @@ Readable.prototype.resume = function() { var state = this._readableState; if (!state.flowing) { state.flowing = true; - if (state.length > 0) { - emitData(this, readBuffer(this)); - } + this.read(); } return this; }; @@ -122,7 +116,7 @@ Readable.prototype.error = function(error) { Readable.prototype.push = function(chunk, encoding) { var state = this._readableState; - if (util.isNull(chunk)) { + if (chunk === null) { onEof(this); } else if (!util.isString(chunk) && !util.isBuffer(chunk)) { @@ -145,6 +139,76 @@ Readable.prototype.push = function(chunk, encoding) { }; +Readable.prototype.pipe = function(destination, options) { + if (!(destination instanceof Writable || isDuplex(destination))) { + throw new TypeError('pipe excepts stream.Writable or' + + ' stream.Duplex as argument'); + } + + options = options || {'end': true}; + + var listeners = { + readableListener: readableListener.bind(this), + dataListener: dataListener.bind(destination), + endListener: endListener.bind(destination), + }; + + this.on('readable', listeners.readableListener); + this.on('data', listeners.dataListener); + + if (options.end) { + this.on('end', listeners.endListener); + } + + this._piped = this._piped || []; + this._piped.push(destination); + + this._piped_listeners = this._piped_listeners || []; + this._piped_listeners.push(listeners); + + return destination; +}; + + +Readable.prototype.unpipe = function(destination) { + if (destination === undefined) { + this.removeAllListeners(); + this._piped = undefined; + this._piped_listeners = undefined; + return; + } + + var idx = this._piped.indexOf(destination); + if (idx === -1) { + return; + } + + this._piped.splice(idx, 1); + var listeners = this._piped_listeners.splice(idx, 1)[0]; + + this.removeListener('readable', listeners.readableListener); + this.removeListener('data', listeners.dataListener); + this.removeListener('end', listeners.endListener); + + return destination; +}; + + +function readableListener() { + this.resume(); +} + + +function dataListener(data) { + this.write(data); +} + + +function endListener() { + this.end(); +} + + function readBuffer(stream, n) { var state = stream._readableState; var res; @@ -159,12 +223,13 @@ function readBuffer(stream, n) { res = Buffer.concat(state.buffer); state.buffer = []; state.length = 0; + emitData(stream, res); } else { throw new Error('not implemented'); } return res; -}; +} function emitEnd(stream) { @@ -177,19 +242,20 @@ function emitEnd(stream) { state.endEmitted = true; stream.emit('end'); } -}; +} function emitData(stream, data) { var state = stream._readableState; - assert.equal(readBuffer(stream), null); - stream.emit('data', data); + if (state.buffer.length === 0 || state.length === 0) { + stream.emit('data', data); + } if (state.ended && state.length == 0) { emitEnd(stream); } -}; +} function onEof(stream) { @@ -200,7 +266,24 @@ function onEof(stream) { if (state.length == 0) { emitEnd(stream); } -}; +} + + +function isDuplex(stream) { + if (!(stream instanceof Readable)) { + return false; + } + + var wr_keys = Object.keys(Writable.prototype); + for (var i = 0; i < wr_keys.length; i++) { + var wr_key = wr_keys[i]; + if (!stream[wr_key]) { + return false; + } + } + + return true; +} module.exports = Readable; diff --git a/src/js/stream_writable.js b/src/js/stream_writable.js index e4b285e32d..db1bdab85f 100644 --- a/src/js/stream_writable.js +++ b/src/js/stream_writable.js @@ -14,10 +14,8 @@ */ -var stream = require('stream'); +var Stream = require('stream_internal'); var util = require('util'); -var Stream = stream.Stream; -var Duplex = stream.Duplex; var defaultHighWaterMark = 128; @@ -36,7 +34,7 @@ function WritableState(options) { this.length = 0; // high water mark. - // The point where write() starts retuning false. + // The point where write() starts returning false. this.highWaterMark = (options && util.isNumber(options.highWaterMark)) ? options.highWaterMark : defaultHighWaterMark; @@ -62,7 +60,7 @@ function WritableState(options) { function Writable(options) { - if (!(this instanceof Writable) && !(this instanceof stream.Duplex)) { + if (!(this instanceof Writable) && options._isDuplex !== true) { return new Writable(options); } @@ -102,21 +100,24 @@ Writable.prototype.write = function(chunk, callback) { // This function object never to be called. concrete stream should override // this method. -Writable.prototype._write = function(chunk, callback, onwrite) { +Writable.prototype._write = function(/* chunk, callback, onwrite */) { throw new Error('unreachable'); -} +}; Writable.prototype.end = function(chunk, callback) { var state = this._writableState; // Because NuttX cannot poll 'EOF',so forcely raise EOF event. - if (process.platform == 'nuttx') { + if (process.platform === 'nuttx') { if (!state.ending) { + var eof = '\\e\\n\\d'; if (util.isNullOrUndefined(chunk)) { - chunk = '\\e\\n\\d'; + chunk = eof; + } else if (Buffer.isBuffer(chunk)) { + chunk = Buffer.concat([chunk, new Buffer(eof)]); } else { - chunk += '\\e\\n\\d'; + chunk += eof; } } } diff --git a/src/js/timers.js b/src/js/timers.js index dedc47327a..1c6c4dd4d3 100644 --- a/src/js/timers.js +++ b/src/js/timers.js @@ -13,26 +13,36 @@ * limitations under the License. */ -var Timer = process.binding(process.binding.timer); - var util = require('util'); -var TIMEOUT_MAX = 2147483647; // 2^31-1 +var TIMEOUT_MAX = '2147483647.0' - 0; // 2^31-1 + +var TIMER_TYPES = { + setTimeout: 0, + setInterval: 1, + setImmediate: 2, +}; function Timeout(after) { this.after = after; - this.isrepeat = false; + this.isRepeat = false; this.callback = null; this.handler = null; } -Timer.prototype.handleTimeout = function() { - var timeout = this.timeoutObj; // 'this' is Timer object +native.prototype.handleTimeout = function() { + var timeout = this.timeoutObj; // 'this' is native object if (timeout && timeout.callback) { - timeout.callback(); - if (!timeout.isrepeat) { + try { + timeout.callback(); + } catch (e) { + timeout.unref(); + throw e; + } + + if (!timeout.isRepeat) { timeout.unref(); } } @@ -41,9 +51,9 @@ Timer.prototype.handleTimeout = function() { Timeout.prototype.ref = function() { var repeat = 0; - var handler = new Timer(); + var handler = new native(); - if (this.isrepeat) { + if (this.isRepeat) { repeat = this.after; } @@ -64,14 +74,19 @@ Timeout.prototype.unref = function() { } }; -function timeoutConfigurator(isrepeat, callback, delay) { + +function timeoutConfigurator(type, callback, delay) { if (!util.isFunction(callback)) { throw new TypeError('Bad arguments: callback must be a Function'); } - delay *= 1; - if (delay < 1 || delay > TIMEOUT_MAX) { - delay = 1; + if (type === TIMER_TYPES.setImmediate) { + delay = 0; + } else { + delay *= 1; + if (delay < 1 || delay > TIMEOUT_MAX) { + delay = 1; + } } var timeout = new Timeout(delay); @@ -84,14 +99,18 @@ function timeoutConfigurator(isrepeat, callback, delay) { args.splice(0, 0, timeout); timeout.callback = callback.bind.apply(callback, args); } - timeout.isrepeat = isrepeat; + timeout.isRepeat = type == TIMER_TYPES.setInterval; timeout.ref(); return timeout; } -exports.setTimeout = timeoutConfigurator.bind(undefined, false); -exports.setInterval = timeoutConfigurator.bind(undefined, true); +exports.setTimeout = timeoutConfigurator.bind(undefined, + TIMER_TYPES.setTimeout); +exports.setInterval = timeoutConfigurator.bind(undefined, + TIMER_TYPES.setInterval); +exports.setImmediate = timeoutConfigurator.bind(undefined, + TIMER_TYPES.setImmediate); function clearTimeoutBase(timeoutType, timeout) { if (timeout) { diff --git a/src/js/tizen.js b/src/js/tizen.js new file mode 100644 index 0000000000..8af7a9bc04 --- /dev/null +++ b/src/js/tizen.js @@ -0,0 +1,151 @@ +/* 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 Bridge = require('bridge'); +var EventEmitter = require('events').EventEmitter; +var util = require('util'); + +var APP_CONTROL_EVENT_TYPE = 'appControl'; + +var BUNDLE_KEY_OPERATION = '__APP_SVC_OP_TYPE__'; +var BUNDLE_KEY_URI = '__APP_SVC_URI__'; +var BUNDLE_KEY_MIME = '__APP_SVC_MIME_TYPE__'; +var BUNDLE_KEY_LAUNCH_MODE = '__APP_SVC_LAUNCH_MODE__'; +var BUNDLE_KEY_CATEGORY = '__APP_SVC_CATEGORY__'; +var BUNDLE_KEY_PACKAGE = '__APP_SVC_PKG_NAME__'; + +var bridge = new Bridge(native.MODULE_NAME); + +var startsWith = function(searchString, position) { + position = position || 0; + return this.substr(position, searchString.length) === searchString; +}; + + +function ApplicationControl(bundle) { + if (!util.isObject(bundle)) { + return this; + } + + this.operation = bundle[BUNDLE_KEY_OPERATION]; + this.uri = bundle[BUNDLE_KEY_URI]; + this.mime = bundle[BUNDLE_KEY_MIME]; + this.launch_mode = bundle[BUNDLE_KEY_LAUNCH_MODE]; + this.category = bundle[BUNDLE_KEY_CATEGORY]; + this.app_id = bundle[BUNDLE_KEY_PACKAGE]; + + var extra_data = {}; + for (var prop in bundle) { + if (bundle.hasOwnProperty(prop) && !startsWith.call(prop, '__')) { + extra_data[prop] = bundle[prop]; + } + } + this.extra_data = Object.keys(extra_data).length ? extra_data : undefined; + + return this; +} + + +function Bundle(appcontrol) { + if (!util.isObject(appcontrol)) { + return this; + } + + var bundle = this; + + if (util.isString(appcontrol.operation)) { + bundle[BUNDLE_KEY_OPERATION] = appcontrol.operation; + } + + if (util.isString(appcontrol.uri)) { + bundle[BUNDLE_KEY_URI] = appcontrol.uri; + } + + if (util.isString(appcontrol.mime)) { + bundle[BUNDLE_KEY_MIME] = appcontrol.mime; + } + + if (util.isString(appcontrol.launch_mode)) { + if (appcontrol.launch_mode === 'group' || + appcontrol.launch_mode === 'single') { + bundle[BUNDLE_KEY_LAUNCH_MODE] = appcontrol.launch_mode; + } + } + + if (util.isString(appcontrol.category)) { + bundle[BUNDLE_KEY_CATEGORY] = appcontrol.category; + } + + if (util.isString(appcontrol.app_id)) { + bundle[BUNDLE_KEY_PACKAGE] = appcontrol.app_id; + } + + var extra_data = appcontrol.extra_data; + if (util.isObject(extra_data)) { + for (var prop in extra_data) { + if (extra_data.hasOwnProperty(prop)) { + // a bundle is a dictionary which consists of key and value pairs + bundle[prop] = extra_data[prop].toString(); + } + } + } + + return this; +} + + +function on(type, listener) { + var callback = listener; + + if (type === APP_CONTROL_EVENT_TYPE) { + // replace callback for application control + callback = function(msg) { + if (util.isString(msg)) { + try { + var json = JSON.parse(msg); + listener(new ApplicationControl(json)); + } catch (e) { + return; // ignore msg. data should be a json string + } + } + }; + } + + return EventEmitter.prototype.on.call(this, type, callback); +} + + +function launchAppControl(option) { + var bundle = new Bundle(option); + return 'OK' === bridge.sendSync('launchAppControl', JSON.stringify(bundle)); +} + + +var getResPath = function() { + return bridge.sendSync('getResPath', ''); +}; + + +var getDataPath = function() { + return bridge.sendSync('getDataPath', ''); +}; + + +module.exports = util.mixin(native, EventEmitter.prototype, { + launchAppControl: launchAppControl, + getResPath: getResPath, + getDataPath: getDataPath, + on: on, +}); diff --git a/src/js/tls.js b/src/js/tls.js new file mode 100644 index 0000000000..eab02f64e8 --- /dev/null +++ b/src/js/tls.js @@ -0,0 +1,268 @@ +/* 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 Duplex = require('stream').Duplex; + +function TLSSocket(socket, options) { + if (!(this instanceof TLSSocket)) { + return new TLSSocket(socket, options); + } + + if ('_tlsSocket' in socket) { + throw Error('Socket already bound'); + } + + this._socket = socket; + socket._tlsSocket = this; + + Duplex.call(this); + + this.authorized = false; + + this._socket.on('connect', this.onconnect); + this._socket.on('data', this.ondata); + this._socket.on('error', this.onerror); + this._socket.on('close', this.onclose); + if (this._socket instanceof net.Socket) { + this._socket.on('finish', this.onfinish); + } else { + this._socket.on('finish', this.onend); + } + this._socket.on('end', this.onend); + + // Native handle + var secureContext = options.secureContext; + if (!secureContext) { + secureContext = createSecureContext(options); + } + + native.TlsInit(this, options, secureContext); + this._socketState = socket._socketState; + + var self = this; + if (socket._writableState.ready && !options.isServer) { + process.nextTick(function() { + self._native_connect(options.servername || options.host || 'localhost'); + self._native_read(null); + }); + } +} +util.inherits(TLSSocket, Duplex); + +TLSSocket.prototype._native_read = native.read; +TLSSocket.prototype._native_write = native.write; +TLSSocket.prototype._native_connect = native.connect; + +TLSSocket.prototype.connect = function(options, callback) { + this._native_connect(options.servername || options.host || 'localhost'); + + if (util.isFunction(callback)) { + this.on('secureConnect', callback); + } + + this._socket.connect(options); +}; + +TLSSocket.prototype._write = function(chunk, callback, onwrite) { + chunk = this._native_write(chunk); + this._socket.write(chunk, callback); + onwrite(); +}; + +TLSSocket.prototype.end = function(data, callback) { + Duplex.prototype.end.call(this, data, callback); + this._socket.end(); +}; + +TLSSocket.prototype.destroy = function() { + this._socket.destroy(); +}; + +TLSSocket.prototype.destroySoon = function() { + this._socket.destroySoon(); +}; + +TLSSocket.prototype.onconnect = function() { + this._tlsSocket._native_read(null); +}; + +TLSSocket.prototype.encrypted = function() { + return true; +}; + +TLSSocket.prototype.address = function() { + return this._socket.address(); +}; + +TLSSocket.prototype.localAddress = function() { + return this._socket.address().address; +}; + +TLSSocket.prototype.setTimeout = function(msecs, callback) { + return this._socket.setTimeout(msecs, callback); +}; + +TLSSocket.prototype.ondata = function(data) { + var self = this._tlsSocket; + self._native_read(data); +}; + +TLSSocket.prototype.onerror = function(error) { + this._tlsSocket.emit('error', error); +}; + +TLSSocket.prototype.onclose = function() { + this._tlsSocket.emit('close'); +}; + +TLSSocket.prototype.onfinish = function() { + this._tlsSocket.emit('finish'); +}; + +TLSSocket.prototype.onend = function() { + this._tlsSocket.emit('end'); +}; + +TLSSocket.prototype.onwrite = function(data) { + return this._socket.write(data); +}; + +TLSSocket.prototype.onread = function(chunk) { + this.emit('data', chunk); +}; + +TLSSocket.prototype.onhandshakedone = function(error, authorized) { + this.authorized = authorized; + + var server = this._server; + + if (error) { + error = Error('handshake failed'); + + if (server) { + server.emit('tlsClientError', error, this); + } else { + this.emit('error', error); + } + this.end(); + return; + } + + this._readyToWrite(); + + if (server) { + server.emit('secureConnection', this); + } else { + this.emit('secureConnect'); + } +}; + +function tlsConnectionListener(rawSocket) { + var tlsSocket = new TLSSocket(rawSocket, { + isServer: true, + secureContext: this._secureContext, + }); + + tlsSocket._server = this; +} + +function Server(options, listener) { + if (!(this instanceof Server)) { + return new Server(options, listener); + } + + this._secureContext = createSecureContext(options); + + // constructor call + net.Server.call(this, options, tlsConnectionListener); + + if (listener) { + this.on('secureConnection', listener); + } +} +util.inherits(Server, net.Server); + +function createSecureContext(options) { + return new native.TlsContext(options); +} + +function createServer(options, secureConnectionListener) { + return new Server(options, secureConnectionListener); +} + +function connect(arg0, arg1, arg2, callback) { + var options = {}; + if (typeof arg0 == 'object') { + options = Object.create(arg0, { + isServer: { value: false, enumerable: true }, + }); + options.host = options.host || 'localhost'; + options.port = options.port || 443; + options.rejectUnauthorized = options.rejectUnauthorized || false; + callback = arg1; + } else if (typeof arg0 == 'number') { + if (typeof arg1 == 'string') { + if (typeof arg2 == 'object') { + options = Object.create(arg2, { + isServer: { value: false, enumerable: true }, + }); + options.port = arg0; + options.host = arg1; + options.rejectUnauthorized = options.rejectUnauthorized || false; + } else { + options = { + isServer: false, + rejectUnauthorized: false, + port: arg0, + host: arg1, + }; + callback = arg2; + } + } else if (typeof arg1 == 'object') { + options = Object.create(arg1, { + isServer: { value: false, enumerable: true }, + }); + options.port = arg0; + options.host = options.host || 'localhost'; + options.rejectUnauthorized = options.rejectUnauthorized || false; + callback = arg2; + } else { + options = { + isServer: false, + rejectUnauthorized: false, + host: 'localhost', + port: arg0, + }; + callback = arg1; + } + } + + var tlsSocket = new TLSSocket(options.socket || new net.Socket(), options); + if (tlsSocket._socket instanceof net.Socket) { + tlsSocket.connect(options, callback); + } else if (util.isFunction(callback)) { + tlsSocket.on('secureConnect', callback); + } + + return tlsSocket; +} + +exports.TLSSocket = TLSSocket; +exports.Server = Server; +exports.createSecureContext = createSecureContext; +exports.createServer = createServer; +exports.connect = connect; diff --git a/src/js/uart.js b/src/js/uart.js index 253472e717..42579ab2cd 100644 --- a/src/js/uart.js +++ b/src/js/uart.js @@ -15,126 +15,19 @@ var EventEmitter = require('events').EventEmitter; var util = require('util'); -var uart = process.binding(process.binding.uart); -// VALIDATION ARRAYS -var BAUDRATE = [0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400 - , 4800, 9600, 19200, 38400, 57600, 115200, 230400]; -var DATABITS = [5, 6, 7, 8]; +util.mixin(native.prototype, EventEmitter.prototype); -var defaultConfiguration = { - baudRate: 9600, - dataBits: 8 -}; - - -function Uart() { - if (!(this instanceof Uart)) { - return new Uart(); - } -} - -Uart.prototype.open = function(configuration, callback) { - return uartPortOpen(configuration, callback); -}; - - -function uartPortOpen(configuration, callback) { - var _binding = null; - - function UartPort(configuration, callback) { //constructor - var self = this; - - if (util.isObject(configuration)) { - if (!util.isString(configuration.device)) { - throw new TypeError( - 'Bad configuration - device is mandatory and should be String'); - } - } else { - throw new TypeError('Bad arguments - configuration should be Object'); - } - - // validate baud rate - if (!util.isUndefined(configuration.baudRate)) { - if (BAUDRATE.indexOf(configuration.baudRate) === -1) { - throw new TypeError("Invalid 'baudRate': " + configuration.baudRate); - } - } else { - configuration.baudRate = defaultConfiguration.baudRate; - } - - // validate data bits - if (!util.isUndefined(configuration.dataBits)) { - if (DATABITS.indexOf(configuration.dataBits) === -1) { - throw new TypeError("Invalid 'databits': " + configuration.dataBits); - } - } else { - configuration.dataBits = defaultConfiguration.dataBits; - } - - EventEmitter.call(this); - - _binding = new uart(configuration, this, function(err) { - util.isFunction(callback) && callback.call(self, err); +var uart = { + open: function(config, callback) { + var uartPort = new native(config, function(err) { + callback(err); }); + return uartPort; + }, + openSync: function(config) { + return new native(config); + }, +}; - process.on('exit', (function(self) { - return function() { - if (!util.isNull(_binding)) { - self.closeSync(); - } - }; - })(this)); - } - - util.inherits(UartPort, EventEmitter); - - UartPort.prototype.write = function(buffer, callback) { - var self = this; - - if (util.isNull(_binding)) { - throw new Error('UART port is not opened'); - } - - _binding.write(buffer, function(err) { - util.isFunction(callback) && callback.call(self, err); - }); - }; - - UartPort.prototype.writeSync = function(buffer) { - var self = this; - - if (util.isNull(_binding)) { - throw new Error('UART port is not opened'); - } - - _binding.write(buffer); - }; - - UartPort.prototype.close = function(callback) { - var self = this; - - if (util.isNull(_binding)) { - throw new Error('UART port is not opened'); - } - - _binding.close(function(err) { - util.isFunction(callback) && callback.call(self, err); - }); - _binding = null; - }; - - UartPort.prototype.closeSync = function() { - if (util.isNull(_binding)) { - throw new Error('UART port is not opened'); - } - - _binding.close(); - _binding = null; - }; - - return new UartPort(configuration, callback); -} - - -module.exports = Uart; +module.exports = uart; diff --git a/src/js/util.js b/src/js/util.js index 55909ee385..3b9787e856 100644 --- a/src/js/util.js +++ b/src/js/util.js @@ -13,6 +13,8 @@ * limitations under the License. */ +var Buffer = require('buffer'); + function isNull(arg) { return arg === null; @@ -25,7 +27,7 @@ function isUndefined(arg) { function isNullOrUndefined(arg) { - return isNull(arg) || isUndefined(arg); + return arg === null || arg === undefined; } @@ -57,53 +59,97 @@ function isFunction(arg) { } -function isBuffer(arg) { - return arg instanceof Buffer; -} - - function inherits(ctor, superCtor) { ctor.prototype = Object.create(superCtor.prototype, { constructor: { value: ctor, enumerable: false, writable: true, - configurable: true - } + configurable: true, + }, }); -}; +} + +function mixin(target) { + if (isNullOrUndefined(target)) { + throw new TypeError('target cannot be null or undefined'); + } + + for (var i = 1; i < arguments.length; ++i) { + var source = arguments[i]; + if (!isNullOrUndefined(source)) { + for (var prop in source) { + if (source.hasOwnProperty(prop)) { + target[prop] = source[prop]; + } + } + } + } + + return target; +} function format(s) { + var i; if (!isString(s)) { var arrs = []; - for (var i = 0; i < arguments.length; ++i) { - arrs.push(formatValue(arguments[i])); + for (i = 0; i < arguments.length; ++i) { + arrs.push(formatValue(arguments[i])); } return arrs.join(' '); } - var i = 1; + i = 1; var args = arguments; - var str = String(s).replace(/%[sdj%]/g, function(m) { - if (m === '%%') { - return '%'; - } - if (i >= args.length) { - return m; + var arg_string; + var str = ''; + var start = 0; + var end = 0; + + while (end < s.length) { + if (s.charAt(end) !== '%') { + end++; + continue; } - switch (m) { - case '%s': return String(args[i++]); - case '%d': return Number(args[i++]); - case '%j': + + str += s.slice(start, end); + + switch (s.charAt(end + 1)) { + case 's': + arg_string = String(args[i]); + break; + case 'd': + arg_string = Number(args[i]); + break; + case 'j': try { - return JSON.stringify(args[i++]); + arg_string = JSON.stringify(args[i]); } catch (_) { - return '[Circular]'; + arg_string = '[Circular]'; } - default: return m; + break; + case '%': + str += '%'; + start = end = end + 2; + continue; + default: + str = str + '%' + s.charAt(end + 1); + start = end = end + 2; + continue; } - }); + + if (i >= args.length) { + str = str + '%' + s.charAt(end + 1); + } else { + i++; + str += arg_string; + } + + start = end = end + 2; + } + + str += s.slice(start, end); while (i < args.length) { str += ' ' + formatValue(args[i++]); @@ -113,18 +159,30 @@ function format(s) { } function formatValue(v) { - if (isUndefined(v)) { + if (v === undefined) { return 'undefined'; - } else if (isNull(v)) { + } else if (v === null) { return 'null'; + } else if (Array.isArray(v)) { + return '[' + v.toString() + ']'; + } else if (v instanceof Error) { + return v.toString(); + } else if (typeof v === 'object') { + return JSON.stringify(v, null, 2); } else { return v.toString(); } } +function stringToNumber(value, default_value) { + var num = Number(value); + return isNaN(num) ? default_value : num; +} + + function errnoException(err, syscall, original) { - var errname = "error"; // uv.errname(err); + var errname = 'error'; // uv.errname(err); var message = syscall + ' ' + errname; if (original) @@ -136,7 +194,7 @@ function errnoException(err, syscall, original) { e.syscall = syscall; return e; -}; +} function exceptionWithHostPort(err, syscall, address, port, additional) { @@ -158,7 +216,7 @@ function exceptionWithHostPort(err, syscall, address, port, additional) { } return ex; -}; +} exports.isNull = isNull; @@ -170,11 +228,11 @@ exports.isString = isString; exports.isObject = isObject; exports.isFinite = isFinite; exports.isFunction = isFunction; -exports.isBuffer = isBuffer; +exports.isBuffer = Buffer.isBuffer; exports.isArray = Array.isArray; exports.exceptionWithHostPort = exceptionWithHostPort; exports.errnoException = errnoException; - +exports.stringToNumber = stringToNumber; exports.inherits = inherits; - +exports.mixin = mixin; exports.format = format; diff --git a/src/js/websocket.js b/src/js/websocket.js new file mode 100644 index 0000000000..f8cd79df50 --- /dev/null +++ b/src/js/websocket.js @@ -0,0 +1,451 @@ +/* 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; +var tls; +try { + tls = require('tls'); +} catch (e) { + // tls remains undefined; +} + +util.inherits(Websocket, EventEmitter); +util.inherits(WebsocketClient, EventEmitter); +util.inherits(Server, EventEmitter); + +function WebSocketHandle(client) { + this.client = client; + this.pings = []; + this.connected = false; + + native.wsInit(this); +} + +function Websocket(options) { + if (!(this instanceof Websocket)) { + return new Websocket(options); + } + + EventEmitter.call(this); + this._firstMessage = true; + this._handle = new WebSocketHandle(this); + this._secure = false; +} + +function WebsocketClient(socket, handle) { + if (!(this instanceof WebsocketClient)) { + return new WebsocketClient(socket, handle); + } + + if ((tls && (socket instanceof tls.TLSSocket)) || + (socket instanceof net.Socket)) { + this._socket = socket; + this.readyState = 'CONNECTING'; + } else { + this._firstMessage = true; + } + this._handle = handle; + + EventEmitter.call(this); +} + +function ServerHandle() { + this.clients = []; + + native.wsInit(this); +} + +function connectionListener(socket) { + var ws = new WebsocketClient(socket, this._serverHandle); + this._serverHandle.clients.push(ws); + var self = this; + + ws._socket.on('data', function(data) { + if (ws.readyState === 'CONNECTING') { + parseServerHandshakeData(data, ws, self); + } else if (ws.readyState === 'OPEN') { + self._serverHandle.ondata(data, ws); + } + }); +} + +function parseServerHandshakeData(data, client, server) { + data = data.toString(); + var res = data.split('\r\n'); + var method = res[0].split(' '); + + // All header keys are converted to lower case + // to ease the processing of the values. + // Based on the HTTP/1.1 RFC (https://tools.ietf.org/html/rfc7230#section-3.2) + // this conversion is ok as the header field names are case-insensitive. + var headers = { 'connection': '', + 'upgrade': '', + 'host': '', + 'sec-websocket-key': '', + 'sec-websocket-version': -1, + }; + + for (var i = 1; i < res.length; i++) { + var temp = res[i].split(': '); + headers[temp[0].toLowerCase()] = temp[1]; + } + + var response = ''; + if (method[0] === 'GET' && + method[2] === 'HTTP/1.1' && + method[1] === server.path && + headers['connection'].toLowerCase().indexOf('upgrade') !== -1 && + headers['upgrade'].toLowerCase() === 'websocket' && + headers['sec-websocket-version'] === '13') { + response = native.ReceiveHandshakeData( + headers['sec-websocket-key'] + ).toString(); + client.readyState = 'OPEN'; + client._socket.write(response); + server.emit('open', client); + } else { + response = method[2] + ' 400 Bad Request\r\nConnection: Closed\r\n\r\n'; + client._socket.write(response); + } +} + +function Server(options, listener) { + if (!(this instanceof Server)) { + return new Server(options); + } + + EventEmitter.call(this); + var emit_type = 'connection'; + this._netserver = null; + + if (options.server) { + if (tls && (options.server instanceof tls.Server)) { + this._netserver = options.server; + emit_type = 'secureConnection'; + } else if (options.server instanceof net.Server) { + this._netserver = options.server; + } + } else if (options.port) { + if (options.secure == true) { + if (!tls) { + throw new Error('TLS module is required to create a secure server.'); + } + this._netserver = tls.createServer(options); + emit_type = 'secureConnection'; + } else { + this._netserver = net.createServer(options); + } + + this._netserver.listen(options.port); + } else { + throw new Error('One of port or server must be provided as option'); + } + this._netserver.path = options.path || '/'; + + this._netserver.on('error', this.onError); + this._netserver.on(emit_type, connectionListener); + this._netserver._serverHandle = new ServerHandle(); + + if (listener) { + this._netserver.on('open', listener); + } + + this.options = options; +} + +ServerHandle.prototype.ondata = function(data, client) { + native.wsReceive(this, data, client); +}; + +ServerHandle.prototype.onmessage = function(msg, client) { + client.emit('message', msg); +}; + +ServerHandle.prototype.pong = function(msg, client) { + client.emit('ping', msg); + this.sendFrame(native.ping(false, msg, true), client); +}; + +ServerHandle.prototype.onError = function(err, client) { + client.emit('error', err); +}; + +ServerHandle.prototype.sendFrame = function(msg, client) { + if (client._socket._socketState.writable) { + client._socket.write(msg); + } else { + if (this.clients.indexOf(client) > -1) { + this.onError('Underlying socket', client); + } + } +}; + +ServerHandle.prototype.onclose = function(msg, client) { + client.readyState = 'CLOSING'; + if (msg) { + // If there is msg we know the following: + // 4 characters status code (1000-4999) + // rest is msg payload + var msg_str = msg.toString(); + msg = { + code: msg_str.substr(0, 4), + reason: msg_str.substr(4, msg_str.length), + }; + } else { + msg = {}; + } + + client.close(msg); +}; + +Server.prototype.close = function(reason, code) { + var msg = { + code: code || 1000, + reason: reason || 'Connection successfully closed', + }; + + var i = 0; + while (this._netserver._serverHandle.clients.length != 0) { + this._netserver._serverHandle.clients[i].readyState = 'CLOSING'; + this._netserver._serverHandle.clients[i].close(msg); + } + + this._netserver.close(); + this.emit('close', msg); +}; + +Server.prototype.broadcast = function(msg, options) { + if (options) { + var mask = options.mask || true; + var binary = options.binary || false; + var compress = options.compress; + if (compress) { + // Currently not supported, needs zlib + this.onError('Compression is not supported'); + } + } + var buff = native.send(msg, binary, mask, compress); + + var self = this; + this._netserver._serverHandle.clients.forEach(function each(client) { + if (client.readyState === 'OPEN') { + self._netserver._serverHandle.sendFrame(buff, client); + } + }); +}; + +Server.prototype.address = function() { + return this._netserver.address(); +}; + +Server.prototype.onError = function(err) { + this.emit('error', err); +}; + +WebsocketClient.prototype.send = function(message, opts) { + if (opts) { + var mask = opts.mask; + var binary = opts.binary; + var compress = opts.compress; + if (compress) { + // Currently not supported, needs zlib + this._handle.onError('Compression is not supported'); + } + } + var buff = native.send(message, binary, mask, compress); + if (buff) { + this._handle.sendFrame(buff, this); + } +}; + +WebsocketClient.prototype.close = function(msg) { + msg = { + reason: msg.reason || 'Connection successfully closed', + code: msg.code || 1000, + }; + + var buff = native.close(msg.reason, msg.code); + this._handle.sendFrame(buff, this); + this.emit('close', msg); + this._socket.end(); + var id = this._handle.clients.indexOf(this); + this._handle.clients.splice(id, 1); +}; + +WebsocketClient.prototype.onError = function(err) { + this.emit('error', err); +}; + +WebSocketHandle.prototype.onmessage = function(msg) { + this.client.emit('message', msg); +}; + +WebSocketHandle.prototype.ondata = function(data) { + native.wsReceive(this, data, this); +}; + +WebSocketHandle.prototype.onhandshakedone = function(remaining) { + this.client.emit('open'); + this.client._firstMessage = false; + if (remaining) { + this.ondata(remaining); + } +}; + +WebSocketHandle.prototype.onError = function(err) { + this.client.emit('error', err); +}; + +WebSocketHandle.prototype.onclose = function(msg) { + if (msg) { + // If there is msg we know the following: + // 4 characters status code (1000-4999) + // rest is msg payload + var msg_str = msg.toString(); + msg = { + code: msg_str.substr(0, 4), + reason: msg_str.substr(4, msg_str.length), + }; + } else { + msg = {}; + } + + this.client.emit('close', msg); + for (var i = 0; i < this.pings.length; i++) { + clearInterval(this.pings[i].timer); + } + this.client._socket.end(); +}; + +WebSocketHandle.prototype.sendFrame = function(msg, cb) { + if (this.connected) { + if (typeof cb == 'function') { + this.client._socket.write(msg, cb); + } else { + this.client._socket.write(msg); + } + } else { + this.onError('Underlying socket connection is closed'); + } +}; + +WebSocketHandle.prototype.pong = function(msg) { + this.client._socket.write(native.ping(false, msg, true)); +}; + +WebSocketHandle.prototype.onpingresp = function(msg) { + for (var i = 0; i < this.pings.length; i++) { + if (this.pings[i].id == msg) { + clearInterval(this.pings[i].timer); + this.pings[i].callback(msg); + this.pings.splice(i, 1); + return; + } + } +}; + +function sendHandshake(jsref, host, path) { + return native.prepareHandshake(jsref, host, path); +} + +Websocket.prototype.connect = function(url, port, path, callback) { + var host = url.toString() || '127.0.0.1'; + path = path || '/'; + + var emit_type = 'connect'; + + if (host.substr(0, 3) == 'wss') { + this._secure = true; + if (!tls) { + this._handle.onError('TLS module was not found!'); + } + port = port || 443; + host = host.substr(6); + this._socket = tls.connect(port, host); + emit_type = 'secureConnect'; + } else if (host.substr(0, 2) == 'ws') { + port = port || 80; + this._socket = new net.Socket(); + host = host.substr(5); + } else { + port = port || 80; + this._socket = new net.Socket(); + } + + if (typeof callback == 'function') { + this.on('open', callback); + } + + var self = this; + + this._socket.on(emit_type, function() { + self._handle.connected = true; + self._socket.write(sendHandshake(self._handle, host, path)); + }); + + this._socket.on('end', function() { + self._handle.connected = false; + }); + if (emit_type == 'connect') { + this._socket.connect(port, host); + } + + this._socket.on('data', function(data) { + if (self._firstMessage) { + var remaining_data = native.parseHandshakeData(data, self._handle); + self._handle.onhandshakedone(remaining_data); + } else { + self._handle.ondata(data); + } + }); +}; + +Websocket.prototype.close = function(message, code, cb) { + this._handle.sendFrame(native.close(message, code), cb); +}; + +Websocket.prototype.ping = function(message, mask, cb) { + var self = this; + var obj = { + id: message, + callback: cb, + timer: setTimeout(function() { + self.close('Ping timeout limit exceeded', 1002); + }, 30000), + }; + this._handle.pings.push(obj); + this._handle.sendFrame(native.ping(true, message, mask)); +}; + +Websocket.prototype.send = function(message, opts, cb) { + if (opts) { + var mask = opts.mask; + var binary = opts.binary; + var compress = opts.compress; + if (compress) { + // Currently not supported, needs zlib + this._handle.onError('Compression is not supported'); + } + } + var buff = native.send(message, binary, mask, compress); + if (buff) { + this._handle.sendFrame(buff, cb); + } +}; + +exports.Websocket = Websocket; +exports.Server = Server; diff --git a/src/modules.json b/src/modules.json new file mode 100644 index 0000000000..5b50cbaa69 --- /dev/null +++ b/src/modules.json @@ -0,0 +1,417 @@ +{ + "modules": { + "iotjs_basic_modules": { + "require": ["assert", "dns", "http", "net", "stream"] + }, + "iotjs_core_modules": { + "require": ["buffer", "console", "events", "fs", "module", "process", + "timers"] + }, + "adc": { + "platforms": { + "linux": { + "native_files": ["modules/linux/iotjs_module_adc-linux.c"] + }, + "nuttx": { + "native_files": ["modules/nuttx/iotjs_module_adc-nuttx.c"] + }, + "tizenrt": { + "native_files": ["modules/tizenrt/iotjs_module_adc-tizenrt.c"] + }, + "undefined": { + "native_files": ["modules/iotjs_module_adc.c"] + } + }, + "native_files": ["modules/iotjs_module_adc.c", + "modules/iotjs_module_periph_common.c"], + "init": "iotjs_init_adc", + "js_file": "js/adc.js" + }, + "assert": { + "js_file": "js/assert.js", + "require": ["util"] + }, + "ble": { + "js_file": "js/ble.js", + "require": ["ble_hci_socket", "ble_characteristic", "ble_descriptor", + "ble_hci_socket_acl_stream", "ble_hci_socket_bindings", + "ble_hci_socket_crypto", "ble_hci_socket_gap", + "ble_hci_socket_gatt", "ble_hci_socket_hci", + "ble_hci_socket_hci_status", "ble_hci_socket_mgmt", + "ble_hci_socket_smp", "ble_primary_service", "ble_uuid_util"] + }, + "ble_characteristic": { + "js_file": "js/ble_characteristic.js", + "require": ["events", "util"] + }, + "ble_descriptor": { + "js_file": "js/ble_descriptor.js", + "require": ["console"] + }, + "ble_hci_socket_acl_stream": { + "js_file": "js/ble_hci_socket_acl_stream.js", + "require": ["events", "util"] + }, + "ble_hci_socket_bindings": { + "js_file": "js/ble_hci_socket_bindings.js", + "require": ["console", "events", "util", "ble_hci_socket_acl_stream", + "ble_hci_socket_hci", "ble_hci_socket_gap", + "ble_hci_socket_gatt"] + }, + "ble_hci_socket_crypto": { + "js_file": "js/ble_hci_socket_crypto.js" + }, + "ble_hci_socket_gap": { + "js_file": "js/ble_hci_socket_gap.js", + "require": ["console", "events", "util", "ble_hci_socket_hci", + "ble_uuid_util"] + }, + "ble_hci_socket_gatt": { + "js_file": "js/ble_hci_socket_gatt.js", + "require": ["console", "events", "util", "ble_uuid_util"] + }, + "ble_hci_socket_hci": { + "js_file": "js/ble_hci_socket_hci.js", + "require": ["console", "events", "util", "ble_uuid_util", + "ble_hci_socket"] + }, + "ble_hci_socket_hci_status": { + "js_file": "js/ble_hci_socket_hci_status.js" + }, + "ble_hci_socket_mgmt": { + "js_file": "js/ble_hci_socket_mgmt.js", + "require": ["console", "events", "util", "ble_hci_socket"] + }, + "ble_hci_socket_smp": { + "js_file": "js/ble_hci_socket_smp.js", + "require": ["events", "util", "ble_hci_socket_crypto", + "ble_hci_socket_mgmt"] + }, + "ble_primary_service": { + "js_file": "js/ble_primary_service.js", + "require": ["events", "util", "ble_uuid_util"] + }, + "ble_uuid_util": { + "js_file": "js/ble_uuid_util.js" + }, + "ble_hci_socket": { + "platforms": { + "linux": { + "native_files": ["modules/linux/iotjs_module_blehcisocket-linux.c"] + }, + "nuttx": { + "native_files": ["modules/nuttx/iotjs_module_blehcisocket-nuttx.c"] + } + }, + "native_files": ["modules/iotjs_module_blehcisocket.c"], + "init": "iotjs_init_blehcisocket", + "js_file": "js/ble_hci_socket.js", + "require": ["events"] + }, + "buffer": { + "native_files": ["modules/iotjs_module_buffer.c"], + "init": "iotjs_init_buffer", + "js_file": "js/buffer.js", + "require": ["util"] + }, + "console": { + "native_files": ["modules/iotjs_module_console.c"], + "init": "iotjs_init_console", + "js_file": "js/console.js", + "require": ["util"] + }, + "constants": { + "native_files": ["modules/iotjs_module_constants.c"], + "init": "iotjs_init_constants" + }, + "crypto": { + "native_files": ["modules/iotjs_module_crypto.c"], + "init": "iotjs_init_crypto", + "js_file": "js/crypto.js" + }, + "dgram": { + "js_file": "js/dgram.js", + "require": ["events", "udp", "util"] + }, + "dns": { + "native_files": ["modules/iotjs_module_dns.c"], + "init": "iotjs_init_dns", + "js_file": "js/dns.js", + "require": ["util"] + }, + "events": { + "js_file": "js/events.js", + "require": ["util"] + }, + "fs": { + "native_files": ["modules/iotjs_module_fs.c"], + "init": "iotjs_init_fs", + "js_file": "js/fs.js", + "require": ["constants", "util"] + }, + "gpio": { + "platforms": { + "linux": { + "native_files": ["modules/linux/iotjs_module_gpio-linux.c"] + }, + "mocklinux": { + "native_files": ["modules/mock/iotjs_module_gpio-mock.c"] + }, + "nuttx": { + "native_files": ["modules/nuttx/iotjs_module_gpio-nuttx.c"] + }, + "tizen": { + "native_files": ["modules/tizen/iotjs_module_gpio-tizen.c"] + }, + "tizenrt": { + "native_files": ["modules/tizenrt/iotjs_module_gpio-tizenrt.c"] + } + }, + "native_files": ["modules/iotjs_module_gpio.c", + "modules/iotjs_module_periph_common.c"], + "init": "iotjs_init_gpio", + "js_file": "js/gpio.js" + }, + "http": { + "js_file": "js/http.js", + "require": ["http_client", "http_common", "http_incoming", + "http_outgoing", "http_server", "http_parser"] + }, + "http_client": { + "js_file": "js/http_client.js", + "require": ["http_common", "http_outgoing", "http_parser", "net", "util"] + }, + "http_common": { + "js_file": "js/http_common.js", + "require": ["http_incoming", "http_parser"] + }, + "http_incoming": { + "js_file": "js/http_incoming.js", + "require": ["stream", "util"] + }, + "http_outgoing": { + "js_file": "js/http_outgoing.js", + "require": ["stream", "util"] + }, + "http_server": { + "js_file": "js/http_server.js", + "require": ["http_common", "http_outgoing", "net", "util"] + }, + "http_signature": { + "js_file": "js/http_signature.js", + "require": ["tls", "crypto"] + }, + "http_parser": { + "native_files": ["modules/iotjs_module_http_parser.c"], + "init": "iotjs_init_http_parser" + }, + "https": { + "js_file": "js/https.js", + "require": ["http_client", "http_parser", "http_server", "net", "tls"] + }, + "i2c": { + "platforms": { + "linux": { + "native_files": ["modules/linux/iotjs_module_i2c-linux.c"] + }, + "mocklinux": { + "native_files": ["modules/mock/iotjs_module_i2c-mock.c"] + }, + "nuttx": { + "native_files": ["modules/nuttx/iotjs_module_i2c-nuttx.c"] + }, + "tizen": { + "native_files": ["modules/tizen/iotjs_module_i2c-tizen.c"] + }, + "tizenrt": { + "native_files": ["modules/tizenrt/iotjs_module_i2c-tizenrt.c"] + } + }, + "native_files": ["modules/iotjs_module_i2c.c", + "modules/iotjs_module_periph_common.c"], + "init": "iotjs_init_i2c", + "js_file": "js/i2c.js" + }, + "module": { + "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": "iotjs_init_mqtt" + }, + "napi": { + "native_files": ["modules/iotjs_module_dynamicloader.c", + "napi/node_api.c", + "napi/node_api_async.c", + "napi/node_api_env.c", + "napi/node_api_function.c", + "napi/node_api_lifetime.c", + "napi/node_api_module.c", + "napi/node_api_object_wrap.c", + "napi/node_api_property.c", + "napi/node_api_value.c"], + "init": "iotjs_init_dynamicloader" + }, + "net": { + "js_file": "js/net.js", + "require": ["assert", "events", "stream", "tcp", "util"] + }, + "process": { + "native_files": ["modules/iotjs_module_process.c"], + "init": "iotjs_init_process" + }, + "pwm": { + "platforms": { + "linux": { + "native_files": ["modules/linux/iotjs_module_pwm-linux.c"] + }, + "mocklinux": { + "native_files": ["modules/mock/iotjs_module_pwm-mock.c"] + }, + "nuttx": { + "native_files": ["modules/nuttx/iotjs_module_pwm-nuttx.c"] + }, + "tizen": { + "native_files": ["modules/tizen/iotjs_module_pwm-tizen.c"] + }, + "tizenrt": { + "native_files": ["modules/tizenrt/iotjs_module_pwm-tizenrt.c"] + } + }, + "native_files": ["modules/iotjs_module_pwm.c", + "modules/iotjs_module_periph_common.c"], + "init": "iotjs_init_pwm", + "js_file": "js/pwm.js" + }, + "spi": { + "platforms": { + "linux": { + "native_files": ["modules/linux/iotjs_module_spi-linux.c"] + }, + "nuttx": { + "native_files": ["modules/nuttx/iotjs_module_spi-nuttx.c"] + }, + "tizen": { + "native_files": ["modules/tizen/iotjs_module_spi-tizen.c"] + }, + "tizenrt": { + "native_files": ["modules/tizenrt/iotjs_module_spi-tizenrt.c"] + } + }, + "native_files": ["modules/iotjs_module_spi.c", + "modules/iotjs_module_periph_common.c"], + "init": "iotjs_init_spi", + "js_file": "js/spi.js" + }, + "stm32f4dis": { + "platforms": { + "nuttx": { + "native_files": ["modules/nuttx/iotjs_module_stm32f4dis-nuttx.c"] + } + }, + "native_files": ["modules/iotjs_module_stm32f4dis.c"], + "init": "iotjs_init_stm32f4dis" + }, + "stm32f7nucleo": { + "platforms": { + "nuttx": { + "native_files": ["modules/nuttx/iotjs_module_stm32f7nucleo-nuttx.c"] + } + }, + "native_files": ["modules/iotjs_module_stm32f7nucleo.c"], + "init": "iotjs_init_stm32f7nucleo" + }, + "stream": { + "js_file": "js/stream.js", + "require": ["stream_duplex", "stream_internal", "stream_readable", + "stream_writable", "util"] + }, + "stream_duplex": { + "js_file": "js/stream_duplex.js", + "require": ["stream_readable", "stream_writable", "util"] + }, + "stream_internal": { + "js_file": "js/stream_internal.js", + "require": ["events", "util"] + }, + "stream_readable": { + "js_file": "js/stream_readable.js", + "require": ["assert", "util"] + }, + "stream_writable": { + "js_file": "js/stream_writable.js", + "require": ["util"] + }, + "tcp": { + "native_files": ["modules/iotjs_module_tcp.c"], + "init": "iotjs_init_tcp" + }, + "timers": { + "native_files": ["modules/iotjs_module_timer.c"], + "init": "iotjs_init_timer", + "js_file": "js/timers.js", + "require": ["util"] + }, + "tls": { + "native_files": ["modules/iotjs_module_tls.c"], + "init": "iotjs_init_tls", + "js_file": "js/tls.js", + "cmakefile": "../cmake/mbedtls.cmake", + "require": ["net", "util"] + }, + "uart": { + "platforms": { + "linux": { + "native_files": ["modules/linux/iotjs_module_uart-linux.c"] + }, + "nuttx": { + "native_files": ["modules/nuttx/iotjs_module_uart-nuttx.c"] + }, + "tizen": { + "native_files": ["modules/tizen/iotjs_module_uart-tizen.c"] + }, + "tizenrt": { + "native_files": ["modules/tizenrt/iotjs_module_uart-tizenrt.c"] + } + }, + "native_files": ["modules/iotjs_module_uart.c", + "modules/iotjs_module_periph_common.c"], + "init": "iotjs_init_uart", + "js_file": "js/uart.js", + "require": ["events"] + }, + "udp": { + "native_files": ["modules/iotjs_module_udp.c"], + "init": "iotjs_init_udp" + }, + "util": { + "js_file": "js/util.js" + }, + "websocket": { + "native_files": ["modules/iotjs_module_websocket.h", + "modules/iotjs_module_websocket.c"], + "init": "iotjs_init_websocket", + "js_file": "js/websocket.js", + "require": ["crypto", "events", "net", "util"] + }, + "bridge": { + "native_files": ["modules/iotjs_module_bridge.c"], + "init": "iotjs_init_bridge", + "js_file": "js/bridge.js" + }, + "tizen": { + "platforms": { + "tizen": { + "native_files": ["modules/tizen/iotjs_module_tizen-tizen.c"] + } + }, + "native_files": ["modules/iotjs_module_tizen.c"], + "init": "iotjs_init_tizen", + "js_file": "js/tizen.js", + "require": ["bridge", "events", "util"] + } + } +} diff --git a/src/modules/iotjs_module_adc.c b/src/modules/iotjs_module_adc.c index cc714fa5bd..fbafd70d7a 100644 --- a/src/modules/iotjs_module_adc.c +++ b/src/modules/iotjs_module_adc.c @@ -15,272 +15,130 @@ #include "iotjs_def.h" #include "iotjs_module_adc.h" -#include "iotjs_objectwrap.h" +#include "iotjs_uv_request.h" IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(adc); -static iotjs_adc_t* iotjs_adc_instance_from_jval(const iotjs_jval_t* jadc); - - -static iotjs_adc_t* iotjs_adc_create(const iotjs_jval_t* jadc) { - iotjs_adc_t* adc = IOTJS_ALLOC(iotjs_adc_t); - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_adc_t, adc); - iotjs_jobjectwrap_initialize(&_this->jobjectwrap, jadc, - &this_module_native_info); - - return adc; -} +IOTJS_DEFINE_PERIPH_CREATE_FUNCTION(adc); static void iotjs_adc_destroy(iotjs_adc_t* adc) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_adc_t, adc); - iotjs_jobjectwrap_destroy(&_this->jobjectwrap); -#if defined(__linux__) - iotjs_string_destroy(&_this->device); -#endif + iotjs_adc_destroy_platform_data(adc->platform_data); IOTJS_RELEASE(adc); } - -#define THIS iotjs_adc_reqwrap_t* adc_reqwrap - - -static iotjs_adc_reqwrap_t* iotjs_adc_reqwrap_create( - const iotjs_jval_t* jcallback, iotjs_adc_t* adc, AdcOp op) { - iotjs_adc_reqwrap_t* adc_reqwrap = IOTJS_ALLOC(iotjs_adc_reqwrap_t); - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_adc_reqwrap_t, adc_reqwrap); - - iotjs_reqwrap_initialize(&_this->reqwrap, jcallback, (uv_req_t*)&_this->req); - - _this->req_data.op = op; - _this->adc_instance = adc; - return adc_reqwrap; -} - - -static void iotjs_adc_reqwrap_destroy(THIS) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_adc_reqwrap_t, adc_reqwrap); - iotjs_reqwrap_destroy(&_this->reqwrap); - IOTJS_RELEASE(adc_reqwrap); -} - - -static void iotjs_adc_reqwrap_dispatched(THIS) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_adc_reqwrap_t, adc_reqwrap); - iotjs_adc_reqwrap_destroy(adc_reqwrap); -} - - -static uv_work_t* iotjs_adc_reqwrap_req(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_adc_reqwrap_t, adc_reqwrap); - return &_this->req; -} - - -static const iotjs_jval_t* iotjs_adc_reqwrap_jcallback(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_adc_reqwrap_t, adc_reqwrap); - return iotjs_reqwrap_jcallback(&_this->reqwrap); -} - - -static iotjs_adc_t* iotjs_adc_instance_from_jval(const iotjs_jval_t* jadc) { - uintptr_t handle = iotjs_jval_get_object_native_handle(jadc); - return (iotjs_adc_t*)handle; -} - - -iotjs_adc_reqwrap_t* iotjs_adc_reqwrap_from_request(uv_work_t* req) { - return (iotjs_adc_reqwrap_t*)(iotjs_reqwrap_from_request((uv_req_t*)req)); -} - - -iotjs_adc_reqdata_t* iotjs_adc_reqwrap_data(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_adc_reqwrap_t, adc_reqwrap); - return &_this->req_data; -} - - -iotjs_adc_t* iotjs_adc_instance_from_reqwrap(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_adc_reqwrap_t, adc_reqwrap); - return _this->adc_instance; -} - - -#undef THIS - - -static void iotjs_adc_after_work(uv_work_t* work_req, int status) { - iotjs_adc_reqwrap_t* req_wrap = iotjs_adc_reqwrap_from_request(work_req); - iotjs_adc_reqdata_t* req_data = iotjs_adc_reqwrap_data(req_wrap); - iotjs_jargs_t jargs = iotjs_jargs_create(2); - bool result = req_data->result; - - if (status) { - iotjs_jval_t error = iotjs_jval_create_error("System error"); - iotjs_jargs_append_jval(&jargs, &error); - iotjs_jval_destroy(&error); - } else { - switch (req_data->op) { - case kAdcOpOpen: - if (!result) { - iotjs_jargs_append_error(&jargs, "Failed to open ADC device"); - } else { - iotjs_jargs_append_null(&jargs); - } - break; - case kAdcOpRead: - if (!result) { - iotjs_jargs_append_error(&jargs, "Cannot read from ADC device"); - } else { - iotjs_jargs_append_null(&jargs); - iotjs_jargs_append_number(&jargs, req_data->value); - } - break; - case kAdcOpClose: - if (!result) { - iotjs_jargs_append_error(&jargs, "Cannot close ADC device"); - } else { - iotjs_jargs_append_null(&jargs); - } - break; - default: { - IOTJS_ASSERT(!"Unreachable"); - break; - } - } +static void adc_worker(uv_work_t* work_req) { + iotjs_periph_data_t* worker_data = + (iotjs_periph_data_t*)IOTJS_UV_REQUEST_EXTRA_DATA(work_req); + iotjs_adc_t* adc = (iotjs_adc_t*)worker_data->data; + + switch (worker_data->op) { + case kAdcOpOpen: + worker_data->result = iotjs_adc_open(adc); + break; + case kAdcOpRead: + worker_data->result = iotjs_adc_read(adc); + break; + case kAdcOpClose: + worker_data->result = iotjs_adc_close(adc); + break; + default: + IOTJS_ASSERT(!"Invalid Adc Operation"); } - - const iotjs_jval_t* jcallback = iotjs_adc_reqwrap_jcallback(req_wrap); - iotjs_make_callback(jcallback, iotjs_jval_get_undefined(), &jargs); - - iotjs_jargs_destroy(&jargs); - - iotjs_adc_reqwrap_dispatched(req_wrap); } +JS_FUNCTION(adc_constructor) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(1, object); + DJS_CHECK_ARG_IF_EXIST(1, function); -static void iotjs_adc_set_configuration(iotjs_adc_t* adc, - const iotjs_jval_t* jconfiguration) { -#if defined(__linux__) - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_adc_t, adc); - iotjs_jval_t jdevice = - iotjs_jval_get_property(jconfiguration, IOTJS_MAGIC_STRING_DEVICE); - _this->device = iotjs_jval_as_string(&jdevice); - iotjs_jval_destroy(&jdevice); -#elif defined(__NUTTX__) - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_adc_t, adc); - iotjs_jval_t jpin = - iotjs_jval_get_property(jconfiguration, IOTJS_MAGIC_STRING_PIN); - _this->pin = iotjs_jval_as_number(&jpin); - iotjs_jval_destroy(&jpin); -#endif -} + // Create ADC object + const jerry_value_t jadc = JS_GET_THIS(); + iotjs_adc_t* adc = adc_create(jadc); + void* adc_native = NULL; + IOTJS_ASSERT(jerry_get_object_native_pointer(jadc, &adc_native, + &this_module_native_info) && + adc == adc_native); -static void iotjs_adc_read_worker(uv_work_t* work_req) { - ADC_WORKER_INIT; - int32_t value = iotjs_adc_read(adc); + jerry_value_t jconfig; + JS_GET_REQUIRED_ARG_VALUE(0, jconfig, IOTJS_MAGIC_STRING_CONFIG, object); - if (value < 0) { - req_data->result = false; - return; + jerry_value_t config_res = iotjs_adc_set_platform_config(adc, jconfig); + if (jerry_value_is_error(config_res)) { + return config_res; } + IOTJS_ASSERT(jerry_value_is_undefined(config_res)); - req_data->value = value; - req_data->result = true; -} - - -static void iotjs_adc_close_worker(uv_work_t* work_req) { - ADC_WORKER_INIT; + jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(1, function); - // Release driver - if (!iotjs_adc_close(adc)) { - req_data->result = false; - return; + // If the callback doesn't exist, it is completed synchronously. + // Otherwise, it will be executed asynchronously. + if (!jerry_value_is_null(jcallback)) { + iotjs_periph_call_async(adc, jcallback, kAdcOpOpen, adc_worker); + } else if (!iotjs_adc_open(adc)) { + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kAdcOpOpen)); } - req_data->result = true; + return jerry_create_undefined(); } -#define ADC_ASYNC(call, this, jcallback, op) \ - do { \ - uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get()); \ - iotjs_adc_reqwrap_t* req_wrap = \ - iotjs_adc_reqwrap_create(jcallback, this, op); \ - uv_work_t* req = iotjs_adc_reqwrap_req(req_wrap); \ - uv_queue_work(loop, req, iotjs_adc_##call##_worker, iotjs_adc_after_work); \ - } while (0) +JS_FUNCTION(adc_read) { + JS_DECLARE_THIS_PTR(adc, adc); + DJS_CHECK_ARG_IF_EXIST(0, function); + iotjs_periph_call_async(adc, JS_GET_ARG_IF_EXIST(0, function), kAdcOpRead, + adc_worker); -JHANDLER_FUNCTION(AdcConstructor) { - DJHANDLER_CHECK_THIS(object); - DJHANDLER_CHECK_ARGS(2, object, function); + return jerry_create_undefined(); +} - // Create ADC object - const iotjs_jval_t* jadc = JHANDLER_GET_THIS(object); - iotjs_adc_t* adc = iotjs_adc_create(jadc); - IOTJS_ASSERT(adc == iotjs_adc_instance_from_jval(jadc)); +JS_FUNCTION(adc_read_sync) { + JS_DECLARE_THIS_PTR(adc, adc); - iotjs_adc_set_configuration(adc, JHANDLER_GET_ARG(0, object)); + if (!iotjs_adc_read(adc)) { + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kAdcOpRead)); + } - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG(1, function); - ADC_ASYNC(open, adc, jcallback, kAdcOpOpen); + return jerry_create_number(adc->value); } +JS_FUNCTION(adc_close) { + JS_DECLARE_THIS_PTR(adc, adc); + DJS_CHECK_ARG_IF_EXIST(0, function); -JHANDLER_FUNCTION(Read) { - JHANDLER_DECLARE_THIS_PTR(adc, adc); - DJHANDLER_CHECK_ARG_IF_EXIST(0, function); - - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(0, function); + iotjs_periph_call_async(adc, JS_GET_ARG_IF_EXIST(0, function), kAdcOpClose, + adc_worker); - if (jcallback) { - ADC_ASYNC(read, adc, jcallback, kAdcOpRead); - } else { - int32_t value = iotjs_adc_read(adc); - if (value < 0) { - JHANDLER_THROW(COMMON, "ADC Read Error"); - } else { - iotjs_jhandler_return_number(jhandler, value); - } - } + return jerry_create_undefined(); } +JS_FUNCTION(adc_close_sync) { + JS_DECLARE_THIS_PTR(adc, adc); -JHANDLER_FUNCTION(Close) { - JHANDLER_DECLARE_THIS_PTR(adc, adc); - DJHANDLER_CHECK_ARG_IF_EXIST(0, function); - - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(0, function); - - if (jcallback) { - ADC_ASYNC(close, adc, jcallback, kAdcOpClose); - } else { - if (!iotjs_adc_close(adc)) { - JHANDLER_THROW(COMMON, "ADC Close Error"); - } + bool ret = iotjs_adc_close(adc); + if (!ret) { + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kAdcOpClose)); } - iotjs_jhandler_return_null(jhandler); + return jerry_create_undefined(); } +jerry_value_t iotjs_init_adc(void) { + jerry_value_t jadc_cons = jerry_create_external_function(adc_constructor); + jerry_value_t jprototype = jerry_create_object(); -iotjs_jval_t InitAdc() { - iotjs_jval_t jadc = iotjs_jval_create_object(); - iotjs_jval_t jadcConstructor = - iotjs_jval_create_function_with_dispatch(AdcConstructor); - iotjs_jval_set_property_jval(&jadc, IOTJS_MAGIC_STRING_ADC, &jadcConstructor); + iotjs_jval_set_method(jprototype, IOTJS_MAGIC_STRING_READ, adc_read); + iotjs_jval_set_method(jprototype, IOTJS_MAGIC_STRING_READSYNC, adc_read_sync); + iotjs_jval_set_method(jprototype, IOTJS_MAGIC_STRING_CLOSE, adc_close); + iotjs_jval_set_method(jprototype, IOTJS_MAGIC_STRING_CLOSESYNC, + adc_close_sync); - iotjs_jval_t jprototype = iotjs_jval_create_object(); - iotjs_jval_set_method(&jprototype, IOTJS_MAGIC_STRING_READ, Read); - iotjs_jval_set_method(&jprototype, IOTJS_MAGIC_STRING_CLOSE, Close); - iotjs_jval_set_property_jval(&jadcConstructor, IOTJS_MAGIC_STRING_PROTOTYPE, - &jprototype); + iotjs_jval_set_property_jval(jadc_cons, IOTJS_MAGIC_STRING_PROTOTYPE, + jprototype); - iotjs_jval_destroy(&jprototype); - iotjs_jval_destroy(&jadcConstructor); + jerry_release_value(jprototype); - return jadc; + return jadc_cons; } diff --git a/src/modules/iotjs_module_adc.h b/src/modules/iotjs_module_adc.h index 4fd04fd415..187263fcf4 100644 --- a/src/modules/iotjs_module_adc.h +++ b/src/modules/iotjs_module_adc.h @@ -18,64 +18,27 @@ #define IOTJS_MODULE_ADC_H #include "iotjs_def.h" -#include "iotjs_objectwrap.h" -#include "iotjs_reqwrap.h" - - -typedef enum { - kAdcOpOpen, - kAdcOpRead, - kAdcOpClose, -} AdcOp; - - -typedef struct { - iotjs_jobjectwrap_t jobjectwrap; - -#if defined(__linux__) - iotjs_string_t device; -#elif defined(__NUTTX__) - uint32_t pin; -#endif - int32_t device_fd; -} IOTJS_VALIDATED_STRUCT(iotjs_adc_t); +#include "iotjs_module_periph_common.h" +// Forward declaration of platform data. These are only used by platform code. +// Generic ADC module never dereferences platform data pointer. +typedef struct iotjs_adc_platform_data_s iotjs_adc_platform_data_t; typedef struct { + jerry_value_t jobject; + iotjs_adc_platform_data_t* platform_data; int32_t value; +} iotjs_adc_t; - bool result; - AdcOp op; -} iotjs_adc_reqdata_t; - - -typedef struct { - iotjs_reqwrap_t reqwrap; - uv_work_t req; - iotjs_adc_reqdata_t req_data; - iotjs_adc_t* adc_instance; -} IOTJS_VALIDATED_STRUCT(iotjs_adc_reqwrap_t); - - -#define THIS iotjs_adc_reqwrap_t* adc_reqwrap - -iotjs_adc_reqwrap_t* iotjs_adc_reqwrap_from_request(uv_work_t* req); -iotjs_adc_reqdata_t* iotjs_adc_reqwrap_data(THIS); - -iotjs_adc_t* iotjs_adc_instance_from_reqwrap(THIS); - -#undef THIS - - -#define ADC_WORKER_INIT \ - iotjs_adc_reqwrap_t* req_wrap = iotjs_adc_reqwrap_from_request(work_req); \ - iotjs_adc_reqdata_t* req_data = iotjs_adc_reqwrap_data(req_wrap); \ - iotjs_adc_t* adc = iotjs_adc_instance_from_reqwrap(req_wrap); - - -int32_t iotjs_adc_read(iotjs_adc_t* adc); +bool iotjs_adc_read(iotjs_adc_t* adc); bool iotjs_adc_close(iotjs_adc_t* adc); -void iotjs_adc_open_worker(uv_work_t* work_req); - +bool iotjs_adc_open(iotjs_adc_t* adc); + +// Platform-related functions; they are implemented +// by platform code (i.e.: linux, nuttx, tizen). +void iotjs_adc_create_platform_data(iotjs_adc_t* adc); +void iotjs_adc_destroy_platform_data(iotjs_adc_platform_data_t* platform_data); +jerry_value_t iotjs_adc_set_platform_config(iotjs_adc_t* adc, + const jerry_value_t jconfig); #endif /* IOTJS_MODULE_ADC_H */ diff --git a/src/modules/iotjs_module_blehcisocket.c b/src/modules/iotjs_module_blehcisocket.c index 6a12b3083c..0c883ca528 100644 --- a/src/modules/iotjs_module_blehcisocket.c +++ b/src/modules/iotjs_module_blehcisocket.c @@ -48,12 +48,11 @@ IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(blehcisocket); -iotjs_blehcisocket_t* iotjs_blehcisocket_create(const iotjs_jval_t* jble) { - THIS = IOTJS_ALLOC(iotjs_blehcisocket_t); - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_blehcisocket_t, blehcisocket); +iotjs_blehcisocket_t* iotjs_blehcisocket_create(jerry_value_t jble) { + iotjs_blehcisocket_t* blehcisocket = IOTJS_ALLOC(iotjs_blehcisocket_t); - iotjs_jobjectwrap_initialize(&_this->jobjectwrap, jble, - &this_module_native_info); + blehcisocket->jobject = jble; + jerry_set_object_native_pointer(jble, blehcisocket, &this_module_native_info); iotjs_blehcisocket_initialize(blehcisocket); @@ -61,155 +60,144 @@ iotjs_blehcisocket_t* iotjs_blehcisocket_create(const iotjs_jval_t* jble) { } -iotjs_blehcisocket_t* iotjs_blehcisocket_instance_from_jval( - const iotjs_jval_t* jble) { - iotjs_jobjectwrap_t* jobjectwrap = iotjs_jobjectwrap_from_jobject(jble); - return (iotjs_blehcisocket_t*)jobjectwrap; -} - - -static void iotjs_blehcisocket_destroy(THIS) { +static void iotjs_blehcisocket_destroy(iotjs_blehcisocket_t* blehcisocket) { iotjs_blehcisocket_close(blehcisocket); - - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_blehcisocket_t, blehcisocket); - iotjs_jobjectwrap_destroy(&_this->jobjectwrap); IOTJS_RELEASE(blehcisocket); } -JHANDLER_FUNCTION(Start) { - JHANDLER_DECLARE_THIS_PTR(blehcisocket, blehcisocket); - DJHANDLER_CHECK_ARGS(0); +JS_FUNCTION(start) { + JS_DECLARE_THIS_PTR(blehcisocket, blehcisocket); iotjs_blehcisocket_start(blehcisocket); - iotjs_jhandler_return_undefined(jhandler); + return jerry_create_undefined(); } -JHANDLER_FUNCTION(BindRaw) { - JHANDLER_DECLARE_THIS_PTR(blehcisocket, blehcisocket); - JHANDLER_CHECK(ge(iotjs_jhandler_get_arg_length(jhandler), 1)); +JS_FUNCTION(bind_raw) { + JS_DECLARE_THIS_PTR(blehcisocket, blehcisocket); + DJS_CHECK(jargc >= 1); int devId = 0; int* pDevId = NULL; - const iotjs_jval_t* raw = iotjs_jhandler_get_arg(jhandler, 0); - if (iotjs_jval_is_number(raw)) { - devId = iotjs_jval_as_number(raw); + if (jerry_value_is_number(jargv[0])) { + devId = iotjs_jval_as_number(jargv[0]); pDevId = &devId; } int ret = iotjs_blehcisocket_bindRaw(blehcisocket, pDevId); - iotjs_jhandler_return_number(jhandler, ret); + return jerry_create_number(ret); } -JHANDLER_FUNCTION(BindUser) { - JHANDLER_DECLARE_THIS_PTR(blehcisocket, blehcisocket); - DJHANDLER_CHECK_ARGS(1, number); +JS_FUNCTION(bind_user) { + JS_DECLARE_THIS_PTR(blehcisocket, blehcisocket); + DJS_CHECK_ARGS(1, number); - int devId = JHANDLER_GET_ARG(0, number); + int devId = JS_GET_ARG(0, number); int* pDevId = &devId; int ret = iotjs_blehcisocket_bindUser(blehcisocket, pDevId); - iotjs_jhandler_return_number(jhandler, ret); + return jerry_create_number(ret); } -JHANDLER_FUNCTION(BindControl) { - JHANDLER_DECLARE_THIS_PTR(blehcisocket, blehcisocket); - DJHANDLER_CHECK_ARGS(0); +JS_FUNCTION(bind_control) { + JS_DECLARE_THIS_PTR(blehcisocket, blehcisocket); iotjs_blehcisocket_bindControl(blehcisocket); - iotjs_jhandler_return_undefined(jhandler); + return jerry_create_undefined(); } -JHANDLER_FUNCTION(IsDevUp) { - JHANDLER_DECLARE_THIS_PTR(blehcisocket, blehcisocket); - DJHANDLER_CHECK_ARGS(0); +JS_FUNCTION(is_dev_up) { + JS_DECLARE_THIS_PTR(blehcisocket, blehcisocket); bool ret = iotjs_blehcisocket_isDevUp(blehcisocket); - iotjs_jhandler_return_boolean(jhandler, ret); + return jerry_create_boolean(ret); } -JHANDLER_FUNCTION(SetFilter) { - JHANDLER_DECLARE_THIS_PTR(blehcisocket, blehcisocket); - DJHANDLER_CHECK_ARGS(1, object); +JS_FUNCTION(set_filter) { + JS_DECLARE_THIS_PTR(blehcisocket, blehcisocket); + DJS_CHECK_ARGS(1, object); iotjs_bufferwrap_t* buffer = - iotjs_bufferwrap_from_jbuffer(JHANDLER_GET_ARG(0, object)); + iotjs_bufferwrap_from_jbuffer(JS_GET_ARG(0, object)); - iotjs_blehcisocket_setFilter(blehcisocket, iotjs_bufferwrap_buffer(buffer), + iotjs_blehcisocket_setFilter(blehcisocket, buffer->buffer, iotjs_bufferwrap_length(buffer)); - iotjs_jhandler_return_undefined(jhandler); + return jerry_create_undefined(); } -JHANDLER_FUNCTION(Stop) { - JHANDLER_DECLARE_THIS_PTR(blehcisocket, blehcisocket); - DJHANDLER_CHECK_ARGS(0); +JS_FUNCTION(stop) { + JS_DECLARE_THIS_PTR(blehcisocket, blehcisocket); iotjs_blehcisocket_stop(blehcisocket); - iotjs_jhandler_return_undefined(jhandler); + return jerry_create_undefined(); } -JHANDLER_FUNCTION(Write) { - JHANDLER_DECLARE_THIS_PTR(blehcisocket, blehcisocket); - DJHANDLER_CHECK_ARGS(1, object); +JS_FUNCTION(write) { + JS_DECLARE_THIS_PTR(blehcisocket, blehcisocket); + DJS_CHECK_ARGS(1, object); iotjs_bufferwrap_t* buffer = - iotjs_bufferwrap_from_jbuffer(JHANDLER_GET_ARG(0, object)); + iotjs_bufferwrap_from_jbuffer(JS_GET_ARG(0, object)); - iotjs_blehcisocket_write(blehcisocket, iotjs_bufferwrap_buffer(buffer), + iotjs_blehcisocket_write(blehcisocket, buffer->buffer, iotjs_bufferwrap_length(buffer)); - iotjs_jhandler_return_undefined(jhandler); + return jerry_create_undefined(); } -JHANDLER_FUNCTION(BleHciSocketCons) { - DJHANDLER_CHECK_THIS(object); - DJHANDLER_CHECK_ARGS(0); +JS_FUNCTION(blehcisocket_cons) { + DJS_CHECK_THIS(); // Create object - const iotjs_jval_t* jblehcisocket = JHANDLER_GET_THIS(object); + jerry_value_t jblehcisocket = JS_GET_THIS(); iotjs_blehcisocket_t* blehcisocket = iotjs_blehcisocket_create(jblehcisocket); - IOTJS_ASSERT(blehcisocket == - (iotjs_blehcisocket_t*)(iotjs_jval_get_object_native_handle( - jblehcisocket))); + + void* blehcisocket_native = NULL; + IOTJS_ASSERT(jerry_get_object_native_pointer(jblehcisocket, + &blehcisocket_native, + &this_module_native_info) && + blehcisocket == blehcisocket_native); + + return jerry_create_undefined(); } -iotjs_jval_t InitBlehcisocket() { - iotjs_jval_t jblehcisocketCons = - iotjs_jval_create_function_with_dispatch(BleHciSocketCons); +jerry_value_t iotjs_init_blehcisocket(void) { + jerry_value_t jblehcisocketCons = + jerry_create_external_function(blehcisocket_cons); - iotjs_jval_t prototype = iotjs_jval_create_object(); + jerry_value_t prototype = jerry_create_object(); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_START, Start); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_BINDRAW, BindRaw); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_BINDUSER, BindUser); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_BINDCONTROL, - BindControl); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_ISDEVUP, IsDevUp); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_SETFILTER, SetFilter); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_STOP, Stop); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_WRITE, Write); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_START, start); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_BINDRAW, bind_raw); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_BINDUSER, bind_user); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_BINDCONTROL, + bind_control); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_ISDEVUP, is_dev_up); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_SETFILTER, set_filter); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_STOP, stop); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_WRITE, write); - iotjs_jval_set_property_jval(&jblehcisocketCons, IOTJS_MAGIC_STRING_PROTOTYPE, - &prototype); + iotjs_jval_set_property_jval(jblehcisocketCons, IOTJS_MAGIC_STRING_PROTOTYPE, + prototype); - iotjs_jval_destroy(&prototype); + jerry_release_value(prototype); return jblehcisocketCons; } diff --git a/src/modules/iotjs_module_blehcisocket.h b/src/modules/iotjs_module_blehcisocket.h index 2872b49bf7..6a82eb800b 100644 --- a/src/modules/iotjs_module_blehcisocket.h +++ b/src/modules/iotjs_module_blehcisocket.h @@ -38,11 +38,9 @@ #define IOTJS_MODULE_BLE_HCI_SOCKET_H #include "iotjs_def.h" -#include "iotjs_objectwrap.h" -#include "iotjs_reqwrap.h" typedef struct { - iotjs_jobjectwrap_t jobjectwrap; + jerry_value_t jobject; int _mode; int _socket; @@ -52,34 +50,33 @@ typedef struct { int _l2socketCount; uint8_t _address[6]; uint8_t _addressType; -} IOTJS_VALIDATED_STRUCT(iotjs_blehcisocket_t); +} iotjs_blehcisocket_t; -#define THIS iotjs_blehcisocket_t* iotjs_blehcisocket +iotjs_blehcisocket_t* iotjs_blehcisocket_create(jerry_value_t jble); -iotjs_blehcisocket_t* iotjs_blehcisocket_create(const iotjs_jval_t* jble); -iotjs_blehcisocket_t* iotjs_blehcisocket_instance_from_jval( - const iotjs_jval_t* jble); - - -void iotjs_blehcisocket_initialize(THIS); -void iotjs_blehcisocket_close(THIS); -void iotjs_blehcisocket_start(THIS); -int iotjs_blehcisocket_bindRaw(THIS, int* devId); -int iotjs_blehcisocket_bindUser(THIS, int* devId); -void iotjs_blehcisocket_bindControl(THIS); -bool iotjs_blehcisocket_isDevUp(THIS); -void iotjs_blehcisocket_setFilter(THIS, char* data, size_t length); -void iotjs_blehcisocket_poll(THIS); -void iotjs_blehcisocket_stop(THIS); -void iotjs_blehcisocket_write(THIS, char* data, size_t length); -void iotjs_blehcisocket_emitErrnoError(THIS); -int iotjs_blehcisocket_devIdFor(THIS, int* pDevId, bool isUp); -int iotjs_blehcisocket_kernelDisconnectWorkArounds(THIS, int length, - char* data); - -#undef THIS +void iotjs_blehcisocket_initialize(iotjs_blehcisocket_t* iotjs_blehcisocket); +void iotjs_blehcisocket_close(iotjs_blehcisocket_t* iotjs_blehcisocket); +void iotjs_blehcisocket_start(iotjs_blehcisocket_t* iotjs_blehcisocket); +int iotjs_blehcisocket_bindRaw(iotjs_blehcisocket_t* iotjs_blehcisocket, + int* devId); +int iotjs_blehcisocket_bindUser(iotjs_blehcisocket_t* iotjs_blehcisocket, + int* devId); +void iotjs_blehcisocket_bindControl(iotjs_blehcisocket_t* iotjs_blehcisocket); +bool iotjs_blehcisocket_isDevUp(iotjs_blehcisocket_t* iotjs_blehcisocket); +void iotjs_blehcisocket_setFilter(iotjs_blehcisocket_t* iotjs_blehcisocket, + char* data, size_t length); +void iotjs_blehcisocket_poll(iotjs_blehcisocket_t* iotjs_blehcisocket); +void iotjs_blehcisocket_stop(iotjs_blehcisocket_t* iotjs_blehcisocket); +void iotjs_blehcisocket_write(iotjs_blehcisocket_t* iotjs_blehcisocket, + char* data, size_t length); +void iotjs_blehcisocket_emitErrnoError( + iotjs_blehcisocket_t* iotjs_blehcisocket); +int iotjs_blehcisocket_devIdFor(iotjs_blehcisocket_t* iotjs_blehcisocket, + int* pDevId, bool isUp); +int iotjs_blehcisocket_kernelDisconnectWorkArounds( + iotjs_blehcisocket_t* iotjs_blehcisocket, int length, char* data); void iotjs_blehcisocket_poll_cb(uv_poll_t* handle, int status, int events); diff --git a/src/modules/iotjs_module_bridge.c b/src/modules/iotjs_module_bridge.c new file mode 100644 index 0000000000..387b5ef892 --- /dev/null +++ b/src/modules/iotjs_module_bridge.c @@ -0,0 +1,415 @@ +/* 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_def.h" +#include "iotjs_module_bridge.h" +#include + +typedef enum { + CALL_STATUS_ERROR = 0, + CALL_STATUS_INIT, + CALL_STATUS_CALLED, + CALL_STATUS_SETMSG, +} iotjs_bridge_status_t; + +typedef struct _iotjs_bridge_object_t iotjs_bridge_object_t; +typedef struct { + jerry_value_t jobject; + jerry_value_t jcallback; + uv_mutex_t call_lock; + uv_work_t req; + uv_async_t* async; + iotjs_string_t module; + iotjs_string_t command; + iotjs_string_t message; + iotjs_string_t ret_msg; + iotjs_bridge_status_t status; + iotjs_bridge_object_t* bridgeobj; +} iotjs_bridge_call_t; + +struct _iotjs_bridge_object_t { + jerry_value_t jobject; + iotjs_bridge_call_t** calls; + size_t calls_alloc; // allocated size of calls +}; + +typedef struct { + char* module_name; + iotjs_bridge_func callback; +} relation_info_t; + +static relation_info_t* g_module_list = 0; +static unsigned int g_module_count = 0; + +IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(bridge_object); + +static unsigned int iotjs_bridge_init() { + if (g_module_list == 0) { + g_module_list = (relation_info_t*)iotjs_buffer_allocate( + sizeof(relation_info_t) * iotjs_module_count); + IOTJS_ASSERT(g_module_list); + } + return iotjs_module_count; +} + +int iotjs_bridge_register(char* module_name, iotjs_bridge_func callback) { + int empty_slot = -1; + iotjs_bridge_init(); + for (int i = 0; i < (int)iotjs_module_count; i++) { + if (g_module_list[i].module_name == 0) { + if (empty_slot == -1) + empty_slot = i; + } else { + if (strncmp(g_module_list[i].module_name, module_name, + strlen(module_name)) == 0) { + return i; + } + } + } + if (empty_slot != -1) { + g_module_list[empty_slot].module_name = + iotjs_buffer_allocate(strlen(module_name) + 1); + IOTJS_ASSERT(g_module_list[empty_slot].module_name); + strncpy(g_module_list[empty_slot].module_name, module_name, + strlen(module_name)); + g_module_list[empty_slot].callback = callback; + g_module_count++; + } + return empty_slot; +} + +static int iotjs_bridge_call(const char* module_name, const char* command, + const char* message, void* handle) { + int ret = -1; + for (int i = 0; i < (int)iotjs_module_count; i++) { + if (g_module_list[i].module_name != 0) { + if (strncmp(g_module_list[i].module_name, module_name, + strlen(module_name) + 1) == 0) { + g_module_list[i].callback(command, message, handle); + ret = 0; + break; + } + } + } + return ret; +} + +void iotjs_bridge_set_err(void* handle, char* err) { + iotjs_bridge_call_t* bridgecall = (iotjs_bridge_call_t*)handle; + IOTJS_ASSERT(iotjs_string_is_empty(&bridgecall->ret_msg)); + + if (err == NULL) { + err = "internal error"; + } + if (!jerry_value_is_undefined(bridgecall->jcallback)) { + uv_mutex_lock(&bridgecall->call_lock); + } + bridgecall->ret_msg = iotjs_string_create_with_size(err, strlen(err) + 1); + bridgecall->status = CALL_STATUS_ERROR; + + if (bridgecall->async != NULL) { + IOTJS_ASSERT(bridgecall->async->data == bridgecall); + uv_async_send(bridgecall->async); + } + if (!jerry_value_is_undefined(bridgecall->jcallback)) { + uv_mutex_unlock(&bridgecall->call_lock); + } +} + +void iotjs_bridge_set_msg(void* handle, char* msg) { + iotjs_bridge_call_t* bridgecall = (iotjs_bridge_call_t*)handle; + IOTJS_ASSERT(iotjs_string_is_empty(&bridgecall->ret_msg)); + size_t size = 0; + if (msg == NULL) { + msg = ""; + } else { + size = strlen(msg) + 1; + } + if (size > MAX_RETURN_MESSAGE) { + iotjs_bridge_set_err(handle, "The message exceeds the maximum"); + } else { + if (!jerry_value_is_undefined(bridgecall->jcallback)) { + uv_mutex_lock(&bridgecall->call_lock); + } + bridgecall->ret_msg = iotjs_string_create_with_size(msg, size); + bridgecall->status = CALL_STATUS_SETMSG; + + if (bridgecall->async != NULL) { + IOTJS_ASSERT(bridgecall->async->data == bridgecall); + uv_async_send(bridgecall->async); + } + if (!jerry_value_is_undefined(bridgecall->jcallback)) { + uv_mutex_unlock(&bridgecall->call_lock); + } + } +} + +static iotjs_bridge_call_t* iotjs_bridge_call_init( + iotjs_bridge_call_t* bridgecall, const jerry_value_t bridge, + const jerry_value_t jcallback, iotjs_string_t module, + iotjs_string_t command, iotjs_string_t message) { + if (bridge) { + bridgecall->jobject = jerry_acquire_value(bridge); + } else { + bridgecall->jobject = jerry_create_undefined(); + } + if (!jerry_value_is_null(jcallback)) { + bridgecall->jcallback = jerry_acquire_value(jcallback); + bridgecall->req.data = (void*)bridgecall; + uv_mutex_init(&bridgecall->call_lock); + } else { + bridgecall->jcallback = jerry_create_undefined(); + } + bridgecall->async = NULL; + bridgecall->module = module; + bridgecall->command = command; + bridgecall->message = message; + bridgecall->ret_msg = iotjs_string_create(); + bridgecall->status = CALL_STATUS_INIT; + bridgecall->bridgeobj = NULL; + + return bridgecall; +} + +static void iotjs_bridge_call_destroy(iotjs_bridge_call_t* bridgecall) { + if (!jerry_value_is_undefined(bridgecall->jobject)) { + jerry_release_value(bridgecall->jobject); + } + if (!jerry_value_is_undefined(bridgecall->jcallback)) { + uv_mutex_destroy(&bridgecall->call_lock); + jerry_release_value(bridgecall->jcallback); + } + if (bridgecall->async) { + uv_close((uv_handle_t*)bridgecall->async, NULL); + IOTJS_RELEASE(bridgecall->async); + } + iotjs_string_destroy(&bridgecall->module); + iotjs_string_destroy(&bridgecall->command); + iotjs_string_destroy(&bridgecall->message); + iotjs_string_destroy(&bridgecall->ret_msg); + bridgecall->bridgeobj = NULL; + IOTJS_RELEASE(bridgecall); +} + +static iotjs_bridge_object_t* iotjs_bridge_get_object(jerry_value_t obj_val) { + iotjs_bridge_object_t* bridgeobj = NULL; + if (jerry_get_object_native_pointer(obj_val, (void**)&bridgeobj, + &this_module_native_info)) { + bridgeobj = IOTJS_ALLOC(iotjs_bridge_object_t); + bridgeobj->jobject = obj_val; + bridgeobj->calls = NULL; + bridgeobj->calls_alloc = 0; + jerry_set_object_native_pointer(obj_val, bridgeobj, + &this_module_native_info); + } + IOTJS_ASSERT(bridgeobj != NULL); + IOTJS_ASSERT(bridgeobj->jobject == obj_val); + return bridgeobj; +} + +static void iotjs_bridge_object_destroy(iotjs_bridge_object_t* bridgeobj) { + if (bridgeobj->calls_alloc == 0) { + if (bridgeobj->calls != NULL) { + iotjs_bridge_call_destroy((iotjs_bridge_call_t*)bridgeobj->calls); + } + } else { + for (size_t i = 0; i < bridgeobj->calls_alloc; i++) { + if (bridgeobj->calls[i] != NULL) { + iotjs_bridge_call_destroy(bridgeobj->calls[i]); + } + } + IOTJS_ASSERT(bridgeobj->calls); + iotjs_buffer_release((char*)bridgeobj->calls); + } + IOTJS_RELEASE(bridgeobj); +} + +static int iotjs_bridge_add_call(iotjs_bridge_object_t* bridgeobj, + iotjs_bridge_call_t* callobj) { + IOTJS_ASSERT(bridgeobj); + IOTJS_ASSERT(callobj); + callobj->bridgeobj = bridgeobj; + if (bridgeobj->calls_alloc == 0) { + if (bridgeobj->calls == NULL) { + bridgeobj->calls = (iotjs_bridge_call_t**)callobj; + } else { + iotjs_bridge_call_t* prev_obj = (iotjs_bridge_call_t*)bridgeobj->calls; + bridgeobj->calls = (iotjs_bridge_call_t**)iotjs_buffer_allocate( + sizeof(iotjs_bridge_call_t*) * 4); + bridgeobj->calls_alloc = 4; + bridgeobj->calls[0] = prev_obj; + bridgeobj->calls[1] = callobj; + } + } else { + for (size_t i = 0; i < bridgeobj->calls_alloc; i++) { + if (bridgeobj->calls[i] == 0) { + bridgeobj->calls[i] = callobj; + return bridgeobj->calls_alloc; + } + } + size_t prev_size = sizeof(iotjs_bridge_call_t*) * bridgeobj->calls_alloc; + bridgeobj->calls = + (iotjs_bridge_call_t**)iotjs_buffer_reallocate((char*)bridgeobj->calls, + prev_size * 2); + bridgeobj->calls[bridgeobj->calls_alloc] = callobj; + bridgeobj->calls_alloc *= 2; + } + return bridgeobj->calls_alloc; +} + +static int iotjs_bridge_remove_call(iotjs_bridge_call_t* callobj) { + iotjs_bridge_object_t* bridgeobj = callobj->bridgeobj; + + if (bridgeobj->calls_alloc == 0) { + if (bridgeobj->calls != NULL) { + iotjs_bridge_call_destroy((iotjs_bridge_call_t*)bridgeobj->calls); + bridgeobj->calls = NULL; + } + } else { + for (size_t i = 0; i < bridgeobj->calls_alloc; i++) { + if (bridgeobj->calls[i] == callobj) { + iotjs_bridge_call_destroy(bridgeobj->calls[i]); + bridgeobj->calls[i] = NULL; + } + } + } + return 0; +} + +static void iotjs_bridge_js_call(iotjs_bridge_call_t* bridgecall) { + jerry_value_t jargs[2] = { 0 }; + if (bridgecall->status == CALL_STATUS_ERROR) { // internal error + jargs[0] = iotjs_jval_create_error_without_error_flag( + iotjs_string_data(&bridgecall->ret_msg)); + jargs[1] = jerry_create_null(); + } else { + jargs[0] = jerry_create_null(); + jargs[1] = jerry_create_string_from_utf8( + (const jerry_char_t*)iotjs_string_data(&bridgecall->ret_msg)); + } + jerry_value_t jcallback = bridgecall->jcallback; + if (jerry_value_is_function(jcallback)) { + iotjs_invoke_callback(jcallback, jerry_create_undefined(), jargs, 2); + } + jerry_release_value(jargs[0]); + jerry_release_value(jargs[1]); +} + +static void aysnc_callback(uv_async_t* async) { + iotjs_bridge_call_t* bridgecall = (iotjs_bridge_call_t*)async->data; + iotjs_bridge_js_call(bridgecall); + iotjs_bridge_remove_call(bridgecall); +} + +void after_worker(uv_work_t* req, int status) { + iotjs_bridge_call_t* bridgecall = (iotjs_bridge_call_t*)req->data; + uv_mutex_lock(&bridgecall->call_lock); + if ((bridgecall->status == CALL_STATUS_ERROR) || + (bridgecall->status == CALL_STATUS_SETMSG)) { + iotjs_bridge_js_call(bridgecall); + uv_mutex_unlock(&bridgecall->call_lock); + iotjs_bridge_remove_call(bridgecall); + } 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); + } +} + +void bridge_worker(uv_work_t* req) { + iotjs_bridge_call_t* bridgecall = (iotjs_bridge_call_t*)req->data; + bridgecall->status = CALL_STATUS_CALLED; + int ret = iotjs_bridge_call(iotjs_string_data(&bridgecall->module), + iotjs_string_data(&bridgecall->command), + iotjs_string_data(&bridgecall->message), + (void*)bridgecall); + if (ret < 0) { + iotjs_bridge_set_err(bridgecall, "Can't find the module"); + } +} + +/** + * send async message + */ +JS_FUNCTION(message_async) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(3, string, string, string); + DJS_CHECK_ARG_IF_EXIST(3, function); + + jerry_value_t bridge_module = JS_GET_THIS(); + iotjs_string_t module_name = JS_GET_ARG(0, string); + iotjs_string_t module_command = JS_GET_ARG(1, string); + iotjs_string_t command_message = JS_GET_ARG(2, string); + jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(3, function); + + if (!jerry_value_is_null(jcallback)) { // async call + uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get()); + iotjs_bridge_object_t* bridgeobj = iotjs_bridge_get_object(bridge_module); + iotjs_bridge_call_t* bridgecall = IOTJS_ALLOC(iotjs_bridge_call_t); + iotjs_bridge_call_init(bridgecall, bridge_module, jcallback, module_name, + module_command, command_message); + iotjs_bridge_add_call(bridgeobj, bridgecall); + + uv_queue_work(loop, &bridgecall->req, bridge_worker, after_worker); + + } else { // sync call + jerry_value_t jmsg; + iotjs_bridge_call_t bridgecall_local; + iotjs_bridge_call_t* bridgecall = &bridgecall_local; + + iotjs_bridge_call_init(bridgecall, 0, 0, module_name, module_command, + command_message); + int ret = iotjs_bridge_call(iotjs_string_data(&module_name), + iotjs_string_data(&module_command), + iotjs_string_data(&command_message), + (void*)bridgecall); + if (ret < 0) { + iotjs_bridge_set_err(bridgecall, "Can't find the module"); + } + if (bridgecall->status == CALL_STATUS_ERROR) { // error.. + if (iotjs_string_is_empty(&bridgecall->ret_msg)) { + jmsg = JS_CREATE_ERROR(COMMON, (jerry_char_t*)"Unknown native error.."); + } else { + jmsg = JS_CREATE_ERROR(COMMON, iotjs_string_data(&bridgecall->ret_msg)); + } + } else { + if (iotjs_string_is_empty(&bridgecall->ret_msg)) { + jmsg = jerry_create_string((jerry_char_t*)""); + } else { + jmsg = jerry_create_string( + (jerry_char_t*)iotjs_string_data(&bridgecall->ret_msg)); + } + } + iotjs_string_destroy(&bridgecall->module); + iotjs_string_destroy(&bridgecall->command); + iotjs_string_destroy(&bridgecall->message); + iotjs_string_destroy(&bridgecall->ret_msg); + return jmsg; + } + + return jerry_create_string((jerry_char_t*)""); +} + +/** + * Init method called by IoT.js + */ +jerry_value_t iotjs_init_bridge() { + jerry_value_t messag_module = jerry_create_object(); + iotjs_jval_set_method(messag_module, "send", message_async); + iotjs_bridge_init(); + return messag_module; +} diff --git a/src/modules/iotjs_module_bridge.h b/src/modules/iotjs_module_bridge.h new file mode 100644 index 0000000000..360102e24a --- /dev/null +++ b/src/modules/iotjs_module_bridge.h @@ -0,0 +1,31 @@ +/* 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_BRIDGE_H +#define IOTJS_BRIDGE_H + +#define MAX_RETURN_MESSAGE 512 * 2 + +/* + */ +typedef void (*iotjs_bridge_func)(const char* command, const char* message, + void* return_handle); + +int iotjs_bridge_register(char* module_name, iotjs_bridge_func callback); + +void iotjs_bridge_set_err(void* return_handle, char* err); +void iotjs_bridge_set_msg(void* return_handle, char* msg); + +#endif diff --git a/src/modules/iotjs_module_buffer.c b/src/modules/iotjs_module_buffer.c index f40ecd2a6d..af7fac75a9 100644 --- a/src/modules/iotjs_module_buffer.c +++ b/src/modules/iotjs_module_buffer.c @@ -20,95 +20,91 @@ #include #include +typedef enum { + BUFFER_HEX_ENC = 0, + BUFFER_BASE64_ENC = 1, +} buffer_encoding_type_t; + IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(bufferwrap); -iotjs_bufferwrap_t* iotjs_bufferwrap_create(const iotjs_jval_t* jbuiltin, +iotjs_bufferwrap_t* iotjs_bufferwrap_create(const jerry_value_t jobject, size_t length) { - iotjs_bufferwrap_t* bufferwrap = IOTJS_ALLOC(iotjs_bufferwrap_t); - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_bufferwrap_t, bufferwrap); - - iotjs_jobjectwrap_initialize(&_this->jobjectwrap, jbuiltin, - &this_module_native_info); - if (length > 0) { - _this->length = length; - _this->buffer = iotjs_buffer_allocate(length); - IOTJS_ASSERT(_this->buffer != NULL); - } else { - _this->length = 0; - _this->buffer = NULL; - } + iotjs_bufferwrap_t* bufferwrap = (iotjs_bufferwrap_t*)iotjs_buffer_allocate( + sizeof(iotjs_bufferwrap_t) + length); - IOTJS_ASSERT( - bufferwrap == - (iotjs_bufferwrap_t*)(iotjs_jval_get_object_native_handle(jbuiltin))); + bufferwrap->jobject = jobject; + jerry_set_object_native_pointer(jobject, bufferwrap, + &this_module_native_info); + + bufferwrap->length = length; + IOTJS_ASSERT( + jerry_get_object_native_pointer(jobject, NULL, &this_module_native_info)); return bufferwrap; } static void iotjs_bufferwrap_destroy(iotjs_bufferwrap_t* bufferwrap) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_bufferwrap_t, bufferwrap); - if (_this->buffer != NULL) { - iotjs_buffer_release(_this->buffer); + if (bufferwrap->external_info && bufferwrap->external_info->free_hint) { + ((void (*)(void*))bufferwrap->external_info->free_hint)( + bufferwrap->external_info->free_info); } - iotjs_jobjectwrap_destroy(&_this->jobjectwrap); + + IOTJS_RELEASE(bufferwrap->external_info); IOTJS_RELEASE(bufferwrap); } -iotjs_bufferwrap_t* iotjs_bufferwrap_from_jbuiltin( - const iotjs_jval_t* jbuiltin) { - IOTJS_ASSERT(iotjs_jval_is_object(jbuiltin)); - iotjs_bufferwrap_t* buffer = - (iotjs_bufferwrap_t*)iotjs_jval_get_object_native_handle(jbuiltin); - IOTJS_ASSERT(buffer != NULL); - return buffer; +void iotjs_bufferwrap_set_external_callback(iotjs_bufferwrap_t* bufferwrap, + void* free_hint, void* free_info) { + bufferwrap->external_info = IOTJS_ALLOC(iotjs_bufferwrap_external_info_t); + bufferwrap->external_info->free_hint = free_hint; + bufferwrap->external_info->free_info = free_info; } -iotjs_bufferwrap_t* iotjs_bufferwrap_from_jbuffer(const iotjs_jval_t* jbuffer) { - IOTJS_ASSERT(iotjs_jval_is_object(jbuffer)); - iotjs_jval_t jbuiltin = - iotjs_jval_get_property(jbuffer, IOTJS_MAGIC_STRING__BUILTIN); - iotjs_bufferwrap_t* buffer = iotjs_bufferwrap_from_jbuiltin(&jbuiltin); - iotjs_jval_destroy(&jbuiltin); - return buffer; -} - +iotjs_bufferwrap_t* iotjs_bufferwrap_from_jbuffer(const jerry_value_t jbuffer) { + IOTJS_ASSERT(jerry_value_is_object(jbuffer)); -iotjs_jval_t* iotjs_bufferwrap_jbuiltin(iotjs_bufferwrap_t* bufferwrap) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_bufferwrap_t, bufferwrap); - return iotjs_jobjectwrap_jobject(&_this->jobjectwrap); + void* buffer = NULL; + bool res = jerry_get_object_native_pointer(jbuffer, &buffer, + &this_module_native_info); + IOTJS_ASSERT(res && buffer != NULL); + return buffer; } -iotjs_jval_t iotjs_bufferwrap_jbuffer(iotjs_bufferwrap_t* bufferwrap) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_bufferwrap_t, bufferwrap); - iotjs_jval_t* jbuiltin = iotjs_bufferwrap_jbuiltin(bufferwrap); - return iotjs_jval_get_property(jbuiltin, IOTJS_MAGIC_STRING__BUFFER); +size_t iotjs_bufferwrap_length(iotjs_bufferwrap_t* bufferwrap) { + if (bufferwrap == NULL) { + IOTJS_ASSERT(0); + return 0; + } +#ifndef NDEBUG + jerry_value_t jlength = + iotjs_jval_get_property(bufferwrap->jobject, IOTJS_MAGIC_STRING_LENGTH); + size_t length = iotjs_jval_as_number(jlength); + IOTJS_ASSERT(length == bufferwrap->length); + jerry_release_value(jlength); +#endif + return bufferwrap->length; } -char* iotjs_bufferwrap_buffer(iotjs_bufferwrap_t* bufferwrap) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_bufferwrap_t, bufferwrap); - return _this->buffer; -} +iotjs_bufferwrap_t* iotjs_jbuffer_get_bufferwrap_ptr( + const jerry_value_t jbuffer) { + if (!jerry_value_is_object(jbuffer)) { + return NULL; + } + void* buffer = NULL; + if (jerry_get_object_native_pointer(jbuffer, &buffer, + &this_module_native_info)) { + return (iotjs_bufferwrap_t*)buffer; + } -size_t iotjs_bufferwrap_length(iotjs_bufferwrap_t* bufferwrap) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_bufferwrap_t, bufferwrap); -#ifndef NDEBUG - iotjs_jval_t jbuf = iotjs_bufferwrap_jbuffer(bufferwrap); - iotjs_jval_t jlength = - iotjs_jval_get_property(&jbuf, IOTJS_MAGIC_STRING_LENGTH); - size_t length = iotjs_jval_as_number(&jlength); - IOTJS_ASSERT(length == _this->length); - iotjs_jval_destroy(&jbuf); - iotjs_jval_destroy(&jlength); -#endif - return _this->length; + return NULL; } @@ -123,47 +119,181 @@ static size_t bound_range(size_t index, size_t low, size_t upper) { } -static int8_t hex2bin(char c) { - if (c >= '0' && c <= '9') +static int8_t hex_to_bin(char c) { + if (c >= '0' && c <= '9') { return (int8_t)(c - '0'); - if (c >= 'A' && c <= 'F') + } + if (c >= 'A' && c <= 'F') { return (int8_t)(10 + (c - 'A')); - if (c >= 'a' && c <= 'f') + } + if (c >= 'a' && c <= 'f') { return (int8_t)(10 + (c - 'a')); + } return (int8_t)(-1); } static size_t hex_decode(char* buf, size_t len, const char* src, - const size_t srcLen) { - size_t i; + const size_t src_len) { + const char* buf_start = buf; + const char* buf_end = buf + len; + const char* src_end = src + src_len; + + if ((src_len & 0x1) != 0) { + return 0; + } + + while (src < src_end) { + int8_t a = hex_to_bin(src[0]); + int8_t b = hex_to_bin(src[1]); + + if (a == -1 || b == -1) { + return 0; + } + + if (buf < buf_end) { + *buf++ = (a << 4) | b; + } + + src += 2; + } + + return (size_t)((buf - buf_start) + 1); +} - for (i = 0; i < len && i * 2 + 1 < srcLen; ++i) { - int8_t a = hex2bin(src[i * 2 + 0]); - int8_t b = hex2bin(src[i * 2 + 1]); - if (a == -1 || b == -1) - return i; - buf[i] = (a << 4) | b; + +static int32_t base64_to_bin(char c) { + if (c >= 'A' && c <= 'Z') { + return (int32_t)(c - 'A'); + } + if (c >= 'a' && c <= 'z') { + return (int32_t)(26 + (c - 'a')); + } + if (c >= '0' && c <= '9') { + return (int32_t)(52 + (c - '0')); + } + if (c == '+') { + return 62; + } + if (c == '/') { + return 63; } - return i; + return (int32_t)(-1); +} + + +static size_t base64_decode(char* dst, size_t len, const char* src, + const size_t srcLen) { + if (srcLen == 0) { + return 1; + } + + char* decoded_base64 = NULL; + size_t decoded_len = iotjs_base64_decode(&decoded_base64, src, srcLen); + size_t ret_val = 0; + if (decoded_len) { + char* buf = dst; + char* bufEnd = len > decoded_len ? dst + decoded_len : dst + len; + + char* pos = decoded_base64; + while (buf < bufEnd) { + *buf++ = *pos++; + } + ret_val = (size_t)(buf - dst) + 1; + } + + IOTJS_RELEASE(decoded_base64); + return ret_val; +} + + +size_t iotjs_base64_decode(char** out_buff, const char* src, + const size_t srcLen) { + if ((srcLen & 0x3) != 0 || srcLen == 0) { + return 0; + } + + size_t len = (3 * (srcLen / 4)); + + const char* src_end = src + srcLen; + + if (src_end[-1] == '=') { + src_end--; + len--; + if (src_end[-1] == '=') { + src_end--; + len--; + } + } + + if (*out_buff == NULL) { + *out_buff = IOTJS_CALLOC(len, char); + } + + char* buf = *out_buff; + + const char* bufStart = buf; + const char* bufEnd = buf + len; + + int32_t current_bits = 0; + int32_t shift = 8; + + while (src < src_end) { + int32_t value = base64_to_bin(*src++); + + if (value == -1) { + return 0; + } + + current_bits = (current_bits << 6) | value; + shift -= 2; + + if (shift == 6) { + continue; + } + + int32_t byte = (current_bits >> shift); + current_bits &= (1 << shift) - 1; + + if (shift == 0) { + shift = 8; + } + + if (buf <= bufEnd) { + *buf++ = byte; + } + } + + return (size_t)((buf - bufStart)); +} + + +static size_t iotjs_convert_double_to_sizet(double value) { + size_t new_value; + + if (value < 0 || isnan(value) || isinf(value)) { + new_value = SIZE_MAX; + } else { + new_value = (size_t)value; + } + + return new_value; } int iotjs_bufferwrap_compare(const iotjs_bufferwrap_t* bufferwrap, const iotjs_bufferwrap_t* other) { - const IOTJS_VALIDATED_STRUCT_METHOD(iotjs_bufferwrap_t, bufferwrap); - - const char* other_buffer = other->unsafe.buffer; - size_t other_length = other->unsafe.length; + const char* other_buffer = other->buffer; + size_t other_length = other->length; size_t i = 0; size_t j = 0; - while (i < _this->length && j < other_length) { - if (_this->buffer[i] < other_buffer[j]) { + while (i < bufferwrap->length && j < other_length) { + if (bufferwrap->buffer[i] < other_buffer[j]) { return -1; - } else if (_this->buffer[i] > other_buffer[j]) { + } else if (bufferwrap->buffer[i] > other_buffer[j]) { return 1; } ++i; @@ -171,7 +301,7 @@ int iotjs_bufferwrap_compare(const iotjs_bufferwrap_t* bufferwrap, } if (j < other_length) { return -1; - } else if (i < _this->length) { + } else if (i < bufferwrap->length) { return 1; } return 0; @@ -180,12 +310,11 @@ int iotjs_bufferwrap_compare(const iotjs_bufferwrap_t* bufferwrap, size_t iotjs_bufferwrap_copy_internal(iotjs_bufferwrap_t* bufferwrap, const char* src, size_t src_from, size_t src_to, size_t dst_from) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_bufferwrap_t, bufferwrap); size_t copied = 0; - size_t dst_length = _this->length; + size_t dst_length = bufferwrap->length; for (size_t i = src_from, j = dst_from; i < src_to && j < dst_length; ++i, ++j) { - *(_this->buffer + j) = *(src + i); + *(bufferwrap->buffer + j) = *(src + i); ++copied; } return copied; @@ -194,114 +323,115 @@ size_t iotjs_bufferwrap_copy_internal(iotjs_bufferwrap_t* bufferwrap, size_t iotjs_bufferwrap_copy(iotjs_bufferwrap_t* bufferwrap, const char* src, size_t len) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_bufferwrap_t, bufferwrap); return iotjs_bufferwrap_copy_internal(bufferwrap, src, 0, len, 0); } +static size_t index_normalizer(int64_t index, size_t max_length) { + size_t idx; + if (index < 0) { + if ((size_t)(-index) > max_length) { + idx = SIZE_MAX; + } else { + idx = (size_t)index + max_length; + } + } else { + idx = (size_t)index; + } -iotjs_jval_t iotjs_bufferwrap_create_buffer(size_t len) { - iotjs_jval_t* jglobal = iotjs_jval_get_global_object(); - - iotjs_jval_t jbuffer = - iotjs_jval_get_property(jglobal, IOTJS_MAGIC_STRING_BUFFER); - IOTJS_ASSERT(iotjs_jval_is_function(&jbuffer)); - - iotjs_jargs_t jargs = iotjs_jargs_create(1); - iotjs_jargs_append_number(&jargs, len); + return bound_range(idx, 0, max_length); +} - iotjs_jval_t jres = - iotjs_jhelper_call_ok(&jbuffer, iotjs_jval_get_undefined(), &jargs); - IOTJS_ASSERT(iotjs_jval_is_object(&jres)); +jerry_value_t iotjs_bufferwrap_create_buffer(size_t len) { + jerry_value_t jres_buffer = jerry_create_object(); - iotjs_jargs_destroy(&jargs); - iotjs_jval_destroy(&jbuffer); + iotjs_bufferwrap_create(jres_buffer, len); - return jres; -} + iotjs_jval_set_property_number(jres_buffer, IOTJS_MAGIC_STRING_LENGTH, len); + // Support for 'instanceof' operator + jerry_value_t native_buffer = iotjs_module_get("buffer"); + jerry_value_t jbuffer = + iotjs_jval_get_property(native_buffer, IOTJS_MAGIC_STRING_BUFFER); -JHANDLER_FUNCTION(Buffer) { - DJHANDLER_CHECK_THIS(object); - DJHANDLER_CHECK_ARGS(2, object, number); + if (!jerry_value_is_error(jbuffer) && jerry_value_is_object(jbuffer)) { + jerry_value_t jbuffer_proto = + iotjs_jval_get_property(jbuffer, IOTJS_MAGIC_STRING_PROTOTYPE); - const iotjs_jval_t* jbuiltin = JHANDLER_GET_THIS(object); - const iotjs_jval_t* jbuffer = JHANDLER_GET_ARG(0, object); - size_t length = JHANDLER_GET_ARG(1, number); + if (!jerry_value_is_error(jbuffer_proto) && + jerry_value_is_object(jbuffer_proto)) { + jerry_set_prototype(jres_buffer, jbuffer_proto); + } - iotjs_jval_set_property_jval(jbuiltin, IOTJS_MAGIC_STRING__BUFFER, jbuffer); + jerry_release_value(jbuffer_proto); + } + jerry_release_value(jbuffer); - iotjs_bufferwrap_t* buffer_wrap = iotjs_bufferwrap_create(jbuiltin, length); - IOTJS_UNUSED(buffer_wrap); + return jres_buffer; } -JHANDLER_FUNCTION(Compare) { - JHANDLER_DECLARE_THIS_PTR(bufferwrap, src_buffer_wrap); - DJHANDLER_CHECK_ARGS(1, object); +JS_FUNCTION(buffer_constructor) { + DJS_CHECK_ARGS(2, object, number); - const iotjs_jval_t* jdst_buffer = JHANDLER_GET_ARG(0, object); - iotjs_bufferwrap_t* dst_buffer_wrap = - iotjs_bufferwrap_from_jbuffer(jdst_buffer); + const jerry_value_t jobject = JS_GET_ARG(0, object); + size_t length = JS_GET_ARG(1, number); - int compare = iotjs_bufferwrap_compare(src_buffer_wrap, dst_buffer_wrap); - iotjs_jhandler_return_number(jhandler, compare); + iotjs_bufferwrap_create(jobject, length); + return jerry_create_undefined(); } +JS_FUNCTION(buffer_compare) { + JS_DECLARE_OBJECT_PTR(0, bufferwrap, src_buffer_wrap); + JS_DECLARE_OBJECT_PTR(1, bufferwrap, dst_buffer_wrap); -#define DECLARE_SIZE_T_FROM_DOUBLE(n, d) \ - size_t n; \ - do { \ - if (d < 0 || isnan(d) || isinf(d)) { \ - n = SIZE_MAX; \ - } else { \ - n = (size_t)d; \ - } \ - } while (0) + int compare = iotjs_bufferwrap_compare(src_buffer_wrap, dst_buffer_wrap); + return jerry_create_number(compare); +} -JHANDLER_FUNCTION(Copy) { - JHANDLER_DECLARE_THIS_PTR(bufferwrap, src_buffer_wrap); - DJHANDLER_CHECK_ARGS(4, object, number, number, number); +JS_FUNCTION(buffer_copy) { + DJS_CHECK_ARGS(5, object, object, number, number, number); + JS_DECLARE_OBJECT_PTR(0, bufferwrap, src_buffer_wrap); - const iotjs_jval_t* jdst_buffer = JHANDLER_GET_ARG(0, object); + const jerry_value_t jdst_buffer = JS_GET_ARG(1, object); iotjs_bufferwrap_t* dst_buffer_wrap = iotjs_bufferwrap_from_jbuffer(jdst_buffer); size_t dst_length = iotjs_bufferwrap_length(dst_buffer_wrap); size_t src_length = iotjs_bufferwrap_length(src_buffer_wrap); - DECLARE_SIZE_T_FROM_DOUBLE(dst_start, JHANDLER_GET_ARG(1, number)); + size_t dst_start = iotjs_convert_double_to_sizet(JS_GET_ARG(2, number)); dst_start = bound_range(dst_start, 0, dst_length); - DECLARE_SIZE_T_FROM_DOUBLE(src_start, JHANDLER_GET_ARG(2, number)); + size_t src_start = iotjs_convert_double_to_sizet(JS_GET_ARG(3, number)); src_start = bound_range(src_start, 0, src_length); - DECLARE_SIZE_T_FROM_DOUBLE(src_end, JHANDLER_GET_ARG(3, number)); + size_t src_end = iotjs_convert_double_to_sizet(JS_GET_ARG(4, number)); src_end = bound_range(src_end, 0, src_length); if (src_end < src_start) { src_end = src_start; } - const char* src_data = iotjs_bufferwrap_buffer(src_buffer_wrap); + const char* src_data = src_buffer_wrap->buffer; size_t copied = iotjs_bufferwrap_copy_internal(dst_buffer_wrap, src_data, src_start, src_end, dst_start); - iotjs_jhandler_return_number(jhandler, copied); + return jerry_create_number(copied); } -JHANDLER_FUNCTION(Write) { - JHANDLER_DECLARE_THIS_PTR(bufferwrap, buffer_wrap); - DJHANDLER_CHECK_ARGS(3, string, number, number); +JS_FUNCTION(buffer_write) { + DJS_CHECK_ARGS(4, object, string, number, number); + JS_DECLARE_OBJECT_PTR(0, bufferwrap, buffer_wrap); - iotjs_string_t src = JHANDLER_GET_ARG(0, string); + iotjs_string_t src = JS_GET_ARG(1, string); size_t buffer_length = iotjs_bufferwrap_length(buffer_wrap); - DECLARE_SIZE_T_FROM_DOUBLE(offset, JHANDLER_GET_ARG(1, number)); + size_t offset = iotjs_convert_double_to_sizet(JS_GET_ARG(2, number)); offset = bound_range(offset, 0, buffer_length); - DECLARE_SIZE_T_FROM_DOUBLE(length, JHANDLER_GET_ARG(2, number)); + size_t length = iotjs_convert_double_to_sizet(JS_GET_ARG(3, number)); length = bound_range(length, 0, buffer_length - offset); length = bound_range(length, 0, iotjs_string_size(&src)); @@ -309,21 +439,21 @@ JHANDLER_FUNCTION(Write) { size_t copied = iotjs_bufferwrap_copy_internal(buffer_wrap, src_data, 0, length, offset); - iotjs_jhandler_return_number(jhandler, copied); - iotjs_string_destroy(&src); + + return jerry_create_number(copied); } -JHANDLER_FUNCTION(WriteUInt8) { - JHANDLER_DECLARE_THIS_PTR(bufferwrap, buffer_wrap); - DJHANDLER_CHECK_ARGS(2, number, number); +JS_FUNCTION(buffer_write_uint8) { + DJS_CHECK_ARGS(3, object, number, number); + JS_DECLARE_OBJECT_PTR(0, bufferwrap, buffer_wrap); - const char src[] = { (char)JHANDLER_GET_ARG(0, number) }; + const char src[] = { (char)JS_GET_ARG(1, number) }; size_t length = 1; size_t buffer_length = iotjs_bufferwrap_length(buffer_wrap); - DECLARE_SIZE_T_FROM_DOUBLE(offset, JHANDLER_GET_ARG(1, number)); + size_t offset = iotjs_convert_double_to_sizet(JS_GET_ARG(2, number)); offset = bound_range(offset, 0, buffer_length); length = bound_range(length, 0, buffer_length - offset); length = bound_range(length, 0, 1); @@ -331,83 +461,75 @@ JHANDLER_FUNCTION(WriteUInt8) { size_t copied = iotjs_bufferwrap_copy_internal(buffer_wrap, src, 0, length, offset); - iotjs_jhandler_return_number(jhandler, copied); + return jerry_create_number(copied); } -JHANDLER_FUNCTION(HexWrite) { - JHANDLER_DECLARE_THIS_PTR(bufferwrap, buffer_wrap); - DJHANDLER_CHECK_ARGS(3, string, number, number); +JS_FUNCTION(buffer_write_decode) { + DJS_CHECK_ARGS(5, object, number, string, number, number); + JS_DECLARE_OBJECT_PTR(0, bufferwrap, buffer_wrap); - iotjs_string_t src = JHANDLER_GET_ARG(0, string); + double type = JS_GET_ARG(1, number); + iotjs_string_t src = JS_GET_ARG(2, string); size_t buffer_length = iotjs_bufferwrap_length(buffer_wrap); - DECLARE_SIZE_T_FROM_DOUBLE(offset, JHANDLER_GET_ARG(1, number)); + size_t offset = iotjs_convert_double_to_sizet(JS_GET_ARG(3, number)); offset = bound_range(offset, 0, buffer_length); - DECLARE_SIZE_T_FROM_DOUBLE(length, JHANDLER_GET_ARG(2, number)); + + size_t length = iotjs_convert_double_to_sizet(JS_GET_ARG(4, number)); length = bound_range(length, 0, buffer_length - offset); const char* src_data = iotjs_string_data(&src); unsigned src_length = iotjs_string_size(&src); - char* src_buf = iotjs_buffer_allocate(length); - size_t nbytes = hex_decode(src_buf, length, src_data, src_length); + size_t nbytes; + char* dst_data = buffer_wrap->buffer + offset; + const char* error_msg; - size_t copied = - iotjs_bufferwrap_copy_internal(buffer_wrap, src_buf, 0, nbytes, offset); - - iotjs_jhandler_return_number(jhandler, copied); + if (type == BUFFER_HEX_ENC) { + nbytes = hex_decode(dst_data, length, src_data, src_length); + error_msg = "Invalid hex string"; + } else { + nbytes = base64_decode(dst_data, length, src_data, src_length); + error_msg = "Invalid base64 string"; + } - iotjs_buffer_release(src_buf); iotjs_string_destroy(&src); + + if (nbytes == 0) + return jerry_create_error(JERRY_ERROR_TYPE, (const jerry_char_t*)error_msg); + + return jerry_create_number(nbytes - 1); } -JHANDLER_FUNCTION(ReadUInt8) { - JHANDLER_DECLARE_THIS_PTR(bufferwrap, buffer_wrap); - DJHANDLER_CHECK_ARGS(1, number); +JS_FUNCTION(buffer_read_uint8) { + DJS_CHECK_ARGS(2, object, number); + JS_DECLARE_OBJECT_PTR(0, bufferwrap, buffer_wrap); size_t buffer_length = iotjs_bufferwrap_length(buffer_wrap); - DECLARE_SIZE_T_FROM_DOUBLE(offset, JHANDLER_GET_ARG(0, number)); - offset = bound_range(offset, 0, buffer_length - 1); - char* buffer = iotjs_bufferwrap_buffer(buffer_wrap); + if (buffer_length == 0) { + return jerry_create_number(0); + } - iotjs_jhandler_return_number(jhandler, (uint8_t)buffer[offset]); -} + size_t offset = iotjs_convert_double_to_sizet(JS_GET_ARG(1, number)); + offset = bound_range(offset, 0, buffer_length - 1); + char* buffer = buffer_wrap->buffer; + return jerry_create_number((uint8_t)buffer[offset]); +} -JHANDLER_FUNCTION(Slice) { - JHANDLER_DECLARE_THIS_PTR(bufferwrap, buffer_wrap); - DJHANDLER_CHECK_ARGS(2, number, number); - int64_t start = JHANDLER_GET_ARG(0, number); - int64_t end = JHANDLER_GET_ARG(1, number); - size_t start_idx, end_idx; +JS_FUNCTION(buffer_slice) { + DJS_CHECK_ARGS(3, object, number, number); + JS_DECLARE_OBJECT_PTR(0, bufferwrap, buffer_wrap); - if (start < 0) { - size_t len = iotjs_bufferwrap_length(buffer_wrap); - if ((size_t)(-start) > len) { - start_idx = SIZE_MAX; - } else { - start_idx = (size_t)start + len; - } - } else { - start_idx = (size_t)start; - } - start_idx = bound_range(start_idx, 0, iotjs_bufferwrap_length(buffer_wrap)); - - if (end < 0) { - size_t len = iotjs_bufferwrap_length(buffer_wrap); - if ((size_t)(-end) > len) { - end_idx = SIZE_MAX; - } else { - end_idx = (size_t)end + len; - } - } else { - end_idx = (size_t)end; - } - end_idx = bound_range(end_idx, 0, iotjs_bufferwrap_length(buffer_wrap)); + int64_t start = JS_GET_ARG(1, number); + int64_t end = JS_GET_ARG(2, number); + size_t len = iotjs_bufferwrap_length(buffer_wrap); + size_t start_idx = index_normalizer(start, len); + size_t end_idx = index_normalizer(end, len); if (end_idx < start_idx) { end_idx = start_idx; @@ -415,102 +537,246 @@ JHANDLER_FUNCTION(Slice) { size_t length = (size_t)(end_idx - start_idx); - iotjs_jval_t jnew_buffer = iotjs_bufferwrap_create_buffer(length); + jerry_value_t jnew_buffer = iotjs_bufferwrap_create_buffer(length); iotjs_bufferwrap_t* new_buffer_wrap = - iotjs_bufferwrap_from_jbuffer(&jnew_buffer); - iotjs_bufferwrap_copy_internal(new_buffer_wrap, - iotjs_bufferwrap_buffer(buffer_wrap), + iotjs_bufferwrap_from_jbuffer(jnew_buffer); + iotjs_bufferwrap_copy_internal(new_buffer_wrap, buffer_wrap->buffer, start_idx, end_idx, 0); - iotjs_jhandler_return_jval(jhandler, &jnew_buffer); - iotjs_jval_destroy(&jnew_buffer); + return jnew_buffer; +} + + +static char to_hex_char(uint8_t digit) { + return (char)((digit < 10) ? (digit + '0') : (digit + 'a' - 10)); +} + + +static jerry_value_t to_hex_string(const uint8_t* data, size_t length) { + if (length == 0) { + return jerry_create_string_sz(NULL, 0); + } + + const uint8_t* end = data + length; + + size_t buffer_length = length * 2; + char* buffer = iotjs_buffer_allocate(buffer_length); + const jerry_char_t* str = (const jerry_char_t*)buffer; + + while (data < end) { + *buffer++ = to_hex_char(*data >> 4); + *buffer++ = to_hex_char(*data & 0xf); + data++; + } + + jerry_value_t ret_value = jerry_create_string_sz(str, buffer_length); + IOTJS_RELEASE(str); + + return ret_value; +} + + +static jerry_value_t to_base64_string(const uint8_t* data, size_t length) { + unsigned char* buffer = NULL; + size_t buffer_length = iotjs_base64_encode(&buffer, data, length); + jerry_value_t ret_value = jerry_create_string_sz(buffer, buffer_length); + IOTJS_RELEASE(buffer); + + return ret_value; +} + +static const unsigned char base64_enc_map[65] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + +size_t iotjs_base64_encode(unsigned char** out_buff, const unsigned char* data, + size_t buff_len) { + size_t i, n; + int C1, C2, C3; + unsigned char* p; + + if (buff_len == 0) { + return 0; + } + + n = buff_len / 3 + (buff_len % 3 != 0); + + if (n > ((size_t)-2) / 4) { + return 0; + } + + if (*out_buff == NULL) { + *out_buff = IOTJS_CALLOC(n * 4 + 1, unsigned char); + } + + n = (buff_len / 3) * 3; + + for (i = 0, p = *out_buff; i < n; i += 3) { + C1 = *data++; + C2 = *data++; + C3 = *data++; + + *p++ = base64_enc_map[(C1 >> 2) & 0x3F]; + *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F]; + *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F]; + *p++ = base64_enc_map[C3 & 0x3F]; + } + + if (i < buff_len) { + C1 = *data++; + C2 = ((i + 1) < buff_len) ? *data++ : 0; + + *p++ = base64_enc_map[(C1 >> 2) & 0x3F]; + *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F]; + + if ((i + 1) < buff_len) { + *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F]; + } else { + *p++ = '='; + } + + *p++ = '='; + } + + size_t ret_len = (size_t)(p - *out_buff); + *p = 0; + + return ret_len; } -JHANDLER_FUNCTION(ToString) { - JHANDLER_DECLARE_THIS_PTR(bufferwrap, buffer_wrap); - DJHANDLER_CHECK_ARGS(2, number, number); +JS_FUNCTION(buffer_to_string) { + DJS_CHECK_ARGS(4, object, number, number, number); + JS_DECLARE_OBJECT_PTR(0, bufferwrap, buffer_wrap); + + double type = JS_GET_ARG(1, number); - DECLARE_SIZE_T_FROM_DOUBLE(start, JHANDLER_GET_ARG(0, number)); + size_t start = iotjs_convert_double_to_sizet(JS_GET_ARG(2, number)); start = bound_range(start, 0, iotjs_bufferwrap_length(buffer_wrap)); - DECLARE_SIZE_T_FROM_DOUBLE(end, JHANDLER_GET_ARG(1, number)); + + size_t end = iotjs_convert_double_to_sizet(JS_GET_ARG(3, number)); end = bound_range(end, 0, iotjs_bufferwrap_length(buffer_wrap)); if (end < start) { end = start; } + if (start > buffer_wrap->length) { + start = buffer_wrap->length; + } + + if (end > buffer_wrap->length) { + end = buffer_wrap->length; + } + size_t length = end - start; - const char* data = iotjs_bufferwrap_buffer(buffer_wrap) + start; + const char* data = buffer_wrap->buffer + start; + + if (type == BUFFER_HEX_ENC) { + return to_hex_string((const uint8_t*)data, length); + } + + if (type == BUFFER_BASE64_ENC) { + return to_base64_string((const uint8_t*)data, length); + } + + /* Stops at first zero. */ length = strnlen(data, length); - iotjs_string_t str = iotjs_string_create_with_size(data, length); - iotjs_jhandler_return_string(jhandler, &str); + if (!jerry_is_valid_utf8_string((const jerry_char_t*)data, length)) { + return JS_CREATE_ERROR(TYPE, "Invalid UTF-8 string"); + } - iotjs_string_destroy(&str); + return jerry_create_string_sz_from_utf8((const jerry_char_t*)data, length); } -JHANDLER_FUNCTION(ToHexString) { - JHANDLER_DECLARE_THIS_PTR(bufferwrap, buffer_wrap); +JS_FUNCTION(buffer_byte_length) { + DJS_CHECK_ARGS(1, string); - size_t length = iotjs_bufferwrap_length(buffer_wrap); - const char* data = iotjs_bufferwrap_buffer(buffer_wrap); + jerry_size_t size = jerry_get_string_size(jargv[0]); + return jerry_create_number(size); +} - char* buffer = iotjs_buffer_allocate(length * 2); - iotjs_string_t str = iotjs_string_create_with_buffer(buffer, length * 2); - for (size_t i = 0; i < length; i++) { - memcpy(buffer, &"0123456789abcdef"[data[i] >> 4 & 0xF], 1); - buffer++; - memcpy(buffer, &"0123456789abcdef"[data[i] >> 0 & 0xF], 1); - buffer++; +JS_FUNCTION(buffer_from_array_buffer) { + if (jargc < 1 || !jerry_value_is_arraybuffer(jargv[0])) { + return jerry_create_undefined(); } + jerry_length_t offset = 0; + jerry_length_t length = jerry_get_arraybuffer_byte_length(jargv[0]); - iotjs_jhandler_return_string(jhandler, &str); - iotjs_string_destroy(&str); -} + if (jargc >= 2) { + jerry_value_t offset_num = jerry_value_to_number(jargv[1]); + if (jerry_value_is_error(offset_num)) { + return offset_num; + } -JHANDLER_FUNCTION(ByteLength) { - DJHANDLER_CHECK_THIS(object); - DJHANDLER_CHECK_ARGS(1, string); + double offset_value = jerry_get_number_value(offset_num); + if (isnan(offset_value)) { + offset_value = 0; + } + jerry_release_value(offset_num); - iotjs_string_t str = JHANDLER_GET_ARG(0, string); - iotjs_jval_t size = iotjs_jval_get_string_size(&str); + if (offset_value < 0 || offset_value > length) { + return JS_CREATE_ERROR(RANGE, "'offset' is out of bounds"); + } + offset = (jerry_length_t)offset_value; + } - iotjs_jhandler_return_jval(jhandler, &size); - iotjs_string_destroy(&str); - iotjs_jval_destroy(&size); -} + length -= offset; + if (jargc >= 3) { + if (jerry_value_is_error(jargv[2])) { + return length; + } -iotjs_jval_t InitBuffer() { - iotjs_jval_t buffer = iotjs_jval_create_function_with_dispatch(Buffer); + if (jerry_value_is_number(jargv[2])) { + double length_value = (double)length; + length_value = jerry_get_number_value(jargv[2]); + + if (isnan(length_value) || length_value < 0) { + length = 0; + } else if (length_value < length) { + length = (jerry_length_t)length_value; + } else if (length_value > length) { + return JS_CREATE_ERROR(RANGE, "'length' is out of bounds"); + } + } + } - iotjs_jval_t prototype = iotjs_jval_create_object(); - iotjs_jval_t byte_length = - iotjs_jval_create_function_with_dispatch(ByteLength); + if (length < 1) { + return iotjs_bufferwrap_create_buffer(0); + } - iotjs_jval_set_property_jval(&buffer, IOTJS_MAGIC_STRING_PROTOTYPE, - &prototype); - iotjs_jval_set_property_jval(&buffer, IOTJS_MAGIC_STRING_BYTELENGTH, - &byte_length); + jerry_value_t jres_bufferwrap = iotjs_bufferwrap_create_buffer(length); + iotjs_bufferwrap_t* jsres_buffer = + iotjs_jbuffer_get_bufferwrap_ptr(jres_bufferwrap); + jerry_arraybuffer_read(jargv[0], offset, (uint8_t*)jsres_buffer->buffer, + length); + return jres_bufferwrap; +} - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_COMPARE, Compare); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_COPY, Copy); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_WRITE, Write); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_HEXWRITE, HexWrite); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_WRITEUINT8, WriteUInt8); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_READUINT8, ReadUInt8); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_SLICE, Slice); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_TOSTRING, ToString); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_TOHEXSTRING, - ToHexString); - iotjs_jval_destroy(&prototype); - iotjs_jval_destroy(&byte_length); +jerry_value_t iotjs_init_buffer(void) { + jerry_value_t buffer = jerry_create_external_function(buffer_constructor); + iotjs_jval_set_method(buffer, IOTJS_MAGIC_STRING_BYTELENGTH, + buffer_byte_length); + iotjs_jval_set_method(buffer, IOTJS_MAGIC_STRING_COMPARE, buffer_compare); + iotjs_jval_set_method(buffer, IOTJS_MAGIC_STRING_COPY, buffer_copy); + iotjs_jval_set_method(buffer, IOTJS_MAGIC_STRING_WRITE, buffer_write); + iotjs_jval_set_method(buffer, IOTJS_MAGIC_STRING_WRITEDECODE, + buffer_write_decode); + iotjs_jval_set_method(buffer, IOTJS_MAGIC_STRING_WRITEUINT8, + buffer_write_uint8); + iotjs_jval_set_method(buffer, IOTJS_MAGIC_STRING_READUINT8, + buffer_read_uint8); + iotjs_jval_set_method(buffer, IOTJS_MAGIC_STRING_SLICE, buffer_slice); + iotjs_jval_set_method(buffer, IOTJS_MAGIC_STRING_TOSTRING, buffer_to_string); + iotjs_jval_set_method(buffer, IOTJS_MAGIC_STRING_FROM_ARRAYBUFFER, + buffer_from_array_buffer); return buffer; } diff --git a/src/modules/iotjs_module_buffer.h b/src/modules/iotjs_module_buffer.h index 2f1e53f4f9..1080abbd80 100644 --- a/src/modules/iotjs_module_buffer.h +++ b/src/modules/iotjs_module_buffer.h @@ -17,37 +17,42 @@ #define IOTJS_MODULE_BUFFER_H -#include "iotjs_objectwrap.h" - +typedef struct { + void* free_hint; + void* free_info; +} iotjs_bufferwrap_external_info_t; typedef struct { - iotjs_jobjectwrap_t jobjectwrap; - char* buffer; + jerry_value_t jobject; size_t length; -} IOTJS_VALIDATED_STRUCT(iotjs_bufferwrap_t); - - -iotjs_bufferwrap_t* iotjs_bufferwrap_create(const iotjs_jval_t* jbuiltin, + iotjs_bufferwrap_external_info_t* external_info; + char buffer[]; +} iotjs_bufferwrap_t; + +size_t iotjs_base64_decode(char** out_buff, const char* src, + const size_t srcLen); +size_t iotjs_base64_encode(unsigned char** out_buff, const uint8_t* data, + size_t length); +iotjs_bufferwrap_t* iotjs_bufferwrap_create(const jerry_value_t jbuiltin, size_t length); -iotjs_bufferwrap_t* iotjs_bufferwrap_from_jbuiltin( - const iotjs_jval_t* jbuiltin); -iotjs_bufferwrap_t* iotjs_bufferwrap_from_jbuffer(const iotjs_jval_t* jbuffer); +void iotjs_bufferwrap_set_external_callback(iotjs_bufferwrap_t* bufferwrap, + void* free_hint, void* free_info); -iotjs_jval_t* iotjs_bufferwrap_jbuiltin(iotjs_bufferwrap_t* bufferwrap); -iotjs_jval_t iotjs_bufferwrap_jbuffer(iotjs_bufferwrap_t* bufferwrap); +iotjs_bufferwrap_t* iotjs_bufferwrap_from_jbuffer(const jerry_value_t jbuffer); -char* iotjs_bufferwrap_buffer(iotjs_bufferwrap_t* bufferwrap); size_t iotjs_bufferwrap_length(iotjs_bufferwrap_t* bufferwrap); int iotjs_bufferwrap_compare(const iotjs_bufferwrap_t* bufferwrap, const iotjs_bufferwrap_t* other); +char* iotjs_bufferwrap_buffer(iotjs_bufferwrap_t* bufferwrap); size_t iotjs_bufferwrap_copy(iotjs_bufferwrap_t* bufferwrap, const char* src, size_t len); +iotjs_bufferwrap_t* iotjs_jbuffer_get_bufferwrap_ptr(const jerry_value_t); -// Create buffer object. -iotjs_jval_t iotjs_bufferwrap_create_buffer(size_t len); +// Fail-safe creation of Buffer object. +jerry_value_t iotjs_bufferwrap_create_buffer(size_t len); #endif /* IOTJS_MODULE_BUFFER_H */ diff --git a/src/modules/iotjs_module_console.c b/src/modules/iotjs_module_console.c index c827636925..68597ebc6a 100644 --- a/src/modules/iotjs_module_console.c +++ b/src/modules/iotjs_module_console.c @@ -14,32 +14,51 @@ */ #include "iotjs_def.h" +#include "iotjs_debuglog.h" +// This function should be able to print utf8 encoded string +// as utf8 is internal string representation in Jerryscript +static jerry_value_t console_print(const jerry_value_t* jargv, + const jerry_length_t jargc, FILE* out_fd) { + DJS_CHECK_ARGS(1, string); + iotjs_string_t msg = JS_GET_ARG(0, string); + const char* str = iotjs_string_data(&msg); + unsigned str_len = iotjs_string_size(&msg); + unsigned idx = 0; -static void Print(iotjs_jhandler_t* jhandler, FILE* out_fd) { - JHANDLER_CHECK_ARGS(1, string); + if (iotjs_console_out) { + int level = (out_fd == stdout) ? DBGLEV_INFO : DBGLEV_ERR; + iotjs_console_out(level, "%s", str); + } else { + for (idx = 0; idx < str_len; idx++) { + if (str[idx] != 0) { + fprintf(out_fd, "%c", str[idx]); + } else { + fprintf(out_fd, "\\u0000"); + } + } + } - iotjs_string_t msg = JHANDLER_GET_ARG(0, string); - fprintf(out_fd, "%s", iotjs_string_data(&msg)); iotjs_string_destroy(&msg); + return jerry_create_undefined(); } -JHANDLER_FUNCTION(Stdout) { - Print(jhandler, stdout); +JS_FUNCTION(console_stdout) { + return console_print(jargv, jargc, stdout); } -JHANDLER_FUNCTION(Stderr) { - Print(jhandler, stderr); +JS_FUNCTION(console_stderr) { + return console_print(jargv, jargc, stderr); } -iotjs_jval_t InitConsole() { - iotjs_jval_t console = iotjs_jval_create_object(); +jerry_value_t iotjs_init_console(void) { + jerry_value_t console = jerry_create_object(); - iotjs_jval_set_method(&console, IOTJS_MAGIC_STRING_STDOUT, Stdout); - iotjs_jval_set_method(&console, IOTJS_MAGIC_STRING_STDERR, Stderr); + iotjs_jval_set_method(console, IOTJS_MAGIC_STRING_STDOUT, console_stdout); + iotjs_jval_set_method(console, IOTJS_MAGIC_STRING_STDERR, console_stderr); return console; } diff --git a/src/modules/iotjs_module_constants.c b/src/modules/iotjs_module_constants.c index a02e675a8f..2880765a52 100644 --- a/src/modules/iotjs_module_constants.c +++ b/src/modules/iotjs_module_constants.c @@ -14,28 +14,28 @@ */ #include "iotjs_def.h" +#include "iotjs_compatibility.h" #include "iotjs_module.h" - #define SET_CONSTANT(object, constant) \ do { \ iotjs_jval_set_property_number(object, #constant, constant); \ } while (0) -iotjs_jval_t InitConstants() { - iotjs_jval_t constants = iotjs_jval_create_object(); +jerry_value_t iotjs_init_constants(void) { + jerry_value_t constants = jerry_create_object(); - SET_CONSTANT(&constants, O_APPEND); - SET_CONSTANT(&constants, O_CREAT); - SET_CONSTANT(&constants, O_EXCL); - SET_CONSTANT(&constants, O_RDONLY); - SET_CONSTANT(&constants, O_RDWR); - SET_CONSTANT(&constants, O_SYNC); - SET_CONSTANT(&constants, O_TRUNC); - SET_CONSTANT(&constants, O_WRONLY); - SET_CONSTANT(&constants, S_IFMT); - SET_CONSTANT(&constants, S_IFDIR); - SET_CONSTANT(&constants, S_IFREG); + SET_CONSTANT(constants, O_APPEND); + SET_CONSTANT(constants, O_CREAT); + SET_CONSTANT(constants, O_EXCL); + SET_CONSTANT(constants, O_RDONLY); + SET_CONSTANT(constants, O_RDWR); + SET_CONSTANT(constants, O_SYNC); + SET_CONSTANT(constants, O_TRUNC); + SET_CONSTANT(constants, O_WRONLY); + SET_CONSTANT(constants, S_IFMT); + SET_CONSTANT(constants, S_IFDIR); + SET_CONSTANT(constants, S_IFREG); return constants; } diff --git a/src/modules/iotjs_module_crypto.c b/src/modules/iotjs_module_crypto.c new file mode 100644 index 0000000000..c5a9eeed98 --- /dev/null +++ b/src/modules/iotjs_module_crypto.c @@ -0,0 +1,542 @@ +/* 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. + */ + +/* + * FIPS-180-1 compliant SHA-1 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * The SHA-1 standard was published by NIST in 1993. + * + * http://www.itl.nist.gov/fipspubs/fip180-1.htm + */ + +#include "iotjs_def.h" +#include "iotjs_module_crypto.h" +#include "iotjs_module_buffer.h" + +/* These enum values are the same as the ones in crypto.js as well as the + corresponding ones in sha.h in mbedTLS.*/ +typedef enum { + IOTJS_CRYPTO_SHA1 = 4, + IOTJS_CRYPTO_SHA256 = 6, +} iotjs_crypto_sha_t; + +#if !ENABLE_MODULE_TLS +const char no_tls_err_str[] = "TLS module must be enabled to use this feature"; + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n, b, i) \ + { \ + (n) = ((uint32_t)(b)[(i)] << 24) | ((uint32_t)(b)[(i) + 1] << 16) | \ + ((uint32_t)(b)[(i) + 2] << 8) | ((uint32_t)(b)[(i) + 3]); \ + } +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n, b, i) \ + { \ + (b)[(i)] = (unsigned char)((n) >> 24); \ + (b)[(i) + 1] = (unsigned char)((n) >> 16); \ + (b)[(i) + 2] = (unsigned char)((n) >> 8); \ + (b)[(i) + 3] = (unsigned char)((n)); \ + } +#endif + +static int iotjs_sha1_process(uint32_t state[5], const unsigned char data[64]) { + uint32_t temp, W[16], A, B, C, D, E; + + GET_UINT32_BE(W[0], data, 0); + GET_UINT32_BE(W[1], data, 4); + GET_UINT32_BE(W[2], data, 8); + GET_UINT32_BE(W[3], data, 12); + GET_UINT32_BE(W[4], data, 16); + GET_UINT32_BE(W[5], data, 20); + GET_UINT32_BE(W[6], data, 24); + GET_UINT32_BE(W[7], data, 28); + GET_UINT32_BE(W[8], data, 32); + GET_UINT32_BE(W[9], data, 36); + GET_UINT32_BE(W[10], data, 40); + GET_UINT32_BE(W[11], data, 44); + GET_UINT32_BE(W[12], data, 48); + GET_UINT32_BE(W[13], data, 52); + GET_UINT32_BE(W[14], data, 56); + GET_UINT32_BE(W[15], data, 60); + +#define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + +#define R(t) \ + (temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ W[(t - 14) & 0x0F] ^ \ + W[t & 0x0F], \ + (W[t & 0x0F] = S(temp, 1))) + +#define P(a, b, c, d, e, x) \ + { \ + e += S(a, 5) + F(b, c, d) + K + x; \ + b = S(b, 30); \ + } + + A = state[0]; + B = state[1]; + C = state[2]; + D = state[3]; + E = state[4]; + +#define F(x, y, z) (z ^ (x & (y ^ z))) +#define K 0x5A827999 + + P(A, B, C, D, E, W[0]); + P(E, A, B, C, D, W[1]); + P(D, E, A, B, C, W[2]); + P(C, D, E, A, B, W[3]); + P(B, C, D, E, A, W[4]); + P(A, B, C, D, E, W[5]); + P(E, A, B, C, D, W[6]); + P(D, E, A, B, C, W[7]); + P(C, D, E, A, B, W[8]); + P(B, C, D, E, A, W[9]); + P(A, B, C, D, E, W[10]); + P(E, A, B, C, D, W[11]); + P(D, E, A, B, C, W[12]); + P(C, D, E, A, B, W[13]); + P(B, C, D, E, A, W[14]); + P(A, B, C, D, E, W[15]); + P(E, A, B, C, D, R(16)); + P(D, E, A, B, C, R(17)); + P(C, D, E, A, B, R(18)); + P(B, C, D, E, A, R(19)); + +#undef K +#undef F + +#define F(x, y, z) (x ^ y ^ z) +#define K 0x6ED9EBA1 + + P(A, B, C, D, E, R(20)); + P(E, A, B, C, D, R(21)); + P(D, E, A, B, C, R(22)); + P(C, D, E, A, B, R(23)); + P(B, C, D, E, A, R(24)); + P(A, B, C, D, E, R(25)); + P(E, A, B, C, D, R(26)); + P(D, E, A, B, C, R(27)); + P(C, D, E, A, B, R(28)); + P(B, C, D, E, A, R(29)); + P(A, B, C, D, E, R(30)); + P(E, A, B, C, D, R(31)); + P(D, E, A, B, C, R(32)); + P(C, D, E, A, B, R(33)); + P(B, C, D, E, A, R(34)); + P(A, B, C, D, E, R(35)); + P(E, A, B, C, D, R(36)); + P(D, E, A, B, C, R(37)); + P(C, D, E, A, B, R(38)); + P(B, C, D, E, A, R(39)); + +#undef K +#undef F + +#define F(x, y, z) ((x & y) | (z & (x | y))) +#define K 0x8F1BBCDC + + P(A, B, C, D, E, R(40)); + P(E, A, B, C, D, R(41)); + P(D, E, A, B, C, R(42)); + P(C, D, E, A, B, R(43)); + P(B, C, D, E, A, R(44)); + P(A, B, C, D, E, R(45)); + P(E, A, B, C, D, R(46)); + P(D, E, A, B, C, R(47)); + P(C, D, E, A, B, R(48)); + P(B, C, D, E, A, R(49)); + P(A, B, C, D, E, R(50)); + P(E, A, B, C, D, R(51)); + P(D, E, A, B, C, R(52)); + P(C, D, E, A, B, R(53)); + P(B, C, D, E, A, R(54)); + P(A, B, C, D, E, R(55)); + P(E, A, B, C, D, R(56)); + P(D, E, A, B, C, R(57)); + P(C, D, E, A, B, R(58)); + P(B, C, D, E, A, R(59)); + +#undef K +#undef F + +#define F(x, y, z) (x ^ y ^ z) +#define K 0xCA62C1D6 + + P(A, B, C, D, E, R(60)); + P(E, A, B, C, D, R(61)); + P(D, E, A, B, C, R(62)); + P(C, D, E, A, B, R(63)); + P(B, C, D, E, A, R(64)); + P(A, B, C, D, E, R(65)); + P(E, A, B, C, D, R(66)); + P(D, E, A, B, C, R(67)); + P(C, D, E, A, B, R(68)); + P(B, C, D, E, A, R(69)); + P(A, B, C, D, E, R(70)); + P(E, A, B, C, D, R(71)); + P(D, E, A, B, C, R(72)); + P(C, D, E, A, B, R(73)); + P(B, C, D, E, A, R(74)); + P(A, B, C, D, E, R(75)); + P(E, A, B, C, D, R(76)); + P(D, E, A, B, C, R(77)); + P(C, D, E, A, B, R(78)); + P(B, C, D, E, A, R(79)); + +#undef K +#undef F + + state[0] += A; + state[1] += B; + state[2] += C; + state[3] += D; + state[4] += E; + + return (0); +} + + +static const unsigned char sha1_padding[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0 }; + + +static int iotjs_sha1_update(uint32_t total[2], uint32_t state[5], + unsigned char buffer[64], + const unsigned char *in_buff, size_t buff_len) { + int ret; + size_t fill; + uint32_t left; + + if (buff_len == 0) { + return 0; + } + + left = total[0] & 0x3F; + fill = 64 - left; + + total[0] += (uint32_t)buff_len; + total[0] &= 0xFFFFFFFF; + + if (total[0] < (uint32_t)buff_len) { + total[1]++; + } + + if (left && buff_len >= fill) { + memcpy((void *)(buffer + left), in_buff, fill); + + if ((ret = iotjs_sha1_process(state, buffer)) != 0) { + return ret; + } + + in_buff += fill; + buff_len -= fill; + left = 0; + } + + while (buff_len >= 64) { + if ((ret = iotjs_sha1_process(state, buffer)) != 0) { + return ret; + } + } + + if (buff_len > 0) { + memcpy((void *)(buffer + left), in_buff, buff_len); + } + + return 0; +} + + +static int iotjs_sha1_finish(uint32_t total[2], uint32_t state[5], + unsigned char buffer[64], + unsigned char *out_buff) { + int ret; + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + + high = (total[0] >> 29) | (total[1] << 3); + low = (total[0] << 3); + + PUT_UINT32_BE(high, msglen, 0); + PUT_UINT32_BE(low, msglen, 4); + + last = total[0] & 0x3F; + padn = (last < 56) ? (56 - last) : (120 - last); + + if ((ret = iotjs_sha1_update(total, state, buffer, sha1_padding, padn)) != + 0) { + return ret; + } + + if ((ret = iotjs_sha1_update(total, state, buffer, msglen, 8)) != 0) { + return ret; + } + + PUT_UINT32_BE(state[0], out_buff, 0); + PUT_UINT32_BE(state[1], out_buff, 4); + PUT_UINT32_BE(state[2], out_buff, 8); + PUT_UINT32_BE(state[3], out_buff, 12); + PUT_UINT32_BE(state[4], out_buff, 16); + + return 0; +} +#else /* ENABLE_MODULE_TLS */ + +#include "mbedtls/pk.h" +#include "mbedtls/sha1.h" +#include "mbedtls/sha256.h" + +#endif /* !ENABLE_MODULE_TLS */ + +size_t iotjs_sha1_encode(unsigned char **out_buff, const unsigned char *in_buff, + size_t buff_len) { + size_t sha1_size = 20; // 160 bytes + *out_buff = IOTJS_CALLOC(sha1_size, unsigned char); +#if !ENABLE_MODULE_TLS + uint32_t total[2] = { 0 }; + uint32_t state[5] = { 0 }; + unsigned char buffer[64] = { 0 }; + + total[0] = 0; + total[1] = 0; + + state[0] = 0x67452301; + state[1] = 0xEFCDAB89; + state[2] = 0x98BADCFE; + state[3] = 0x10325476; + state[4] = 0xC3D2E1F0; + + iotjs_sha1_update(total, state, buffer, in_buff, buff_len); + iotjs_sha1_finish(total, state, buffer, *out_buff); +#else /* ENABLE_MODULE_TLS */ + mbedtls_sha1_context sha_ctx; + mbedtls_sha1_init(&sha_ctx); +#if defined(__TIZENRT__) + mbedtls_sha1_starts(&sha_ctx); + mbedtls_sha1_update(&sha_ctx, in_buff, buff_len); + mbedtls_sha1_finish(&sha_ctx, *out_buff); +#else /* !__TIZENRT__ */ + mbedtls_sha1_starts_ret(&sha_ctx); + mbedtls_sha1_update_ret(&sha_ctx, in_buff, buff_len); + mbedtls_sha1_finish_ret(&sha_ctx, *out_buff); +#endif /* __TIZENRT__ */ + mbedtls_sha1_free(&sha_ctx); +#endif /* ENABLE_MODULE_TLS */ + + return sha1_size; +} + + +#if ENABLE_MODULE_TLS +size_t iotjs_sha256_encode(unsigned char **out_buff, + const unsigned char *in_buff, size_t buff_len) { + size_t sha256_size = 32; + *out_buff = IOTJS_CALLOC(sha256_size, unsigned char); + + mbedtls_sha256_context sha_ctx; + mbedtls_sha256_init(&sha_ctx); +#if defined(__TIZENRT__) + mbedtls_sha256_starts(&sha_ctx, 0); + mbedtls_sha256_update(&sha_ctx, in_buff, buff_len); + mbedtls_sha256_finish(&sha_ctx, *out_buff); +#else /* !__TIZENRT__ */ + mbedtls_sha256_starts_ret(&sha_ctx, 0); + mbedtls_sha256_update_ret(&sha_ctx, in_buff, buff_len); + mbedtls_sha256_finish_ret(&sha_ctx, *out_buff); +#endif /* __TIZENRT__ */ + mbedtls_sha256_free(&sha_ctx); + + return sha256_size; +} +#endif /* ENABLE_MODULE_TLS */ + + +JS_FUNCTION(sha_encode) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(2, any, number); + + uint8_t type = JS_GET_ARG(1, number); + + jerry_value_t jstring = JS_GET_ARG(0, any); + iotjs_string_t user_str = iotjs_string_create(); + + if (!iotjs_jbuffer_as_string(jstring, &user_str)) { + return jerry_create_undefined(); + } + + const unsigned char *user_str_data = + (const unsigned char *)iotjs_string_data(&user_str); + size_t user_str_sz = iotjs_string_size(&user_str); + + size_t sha_sz = 0; + + unsigned char *sha_ret = NULL; + + switch (type) { + case IOTJS_CRYPTO_SHA1: { + sha_sz = iotjs_sha1_encode(&sha_ret, user_str_data, user_str_sz); + break; + } + case IOTJS_CRYPTO_SHA256: { +#if !ENABLE_MODULE_TLS + iotjs_string_destroy(&user_str); + return JS_CREATE_ERROR(COMMON, no_tls_err_str); +#else /* ENABLE_MODULE_TLS */ + sha_sz = iotjs_sha256_encode(&sha_ret, user_str_data, user_str_sz); + break; +#endif /* !ENABLE_MODULE_TLS */ + } + default: { + iotjs_string_destroy(&user_str); + return JS_CREATE_ERROR(COMMON, "Unknown SHA hashing algorithm"); + } + } + + iotjs_string_destroy(&user_str); + + jerry_value_t ret_val; + ret_val = iotjs_bufferwrap_create_buffer(sha_sz); + iotjs_bufferwrap_t *ret_wrap = iotjs_bufferwrap_from_jbuffer(ret_val); + memcpy(ret_wrap->buffer, sha_ret, sha_sz); + ret_wrap->length = sha_sz; + + IOTJS_RELEASE(sha_ret); + return ret_val; +} + + +JS_FUNCTION(rsa_verify) { +#if !ENABLE_MODULE_TLS + return JS_CREATE_ERROR(COMMON, no_tls_err_str); +#else /* ENABLE_MODULE_TLS */ + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(2, any, any); + + uint8_t type = JS_GET_ARG(0, number); + jerry_value_t jdata = JS_GET_ARG(1, any); + jerry_value_t jkey = JS_GET_ARG(2, any); + jerry_value_t jsignature = JS_GET_ARG(3, any); + + iotjs_string_t key = iotjs_string_create(); + iotjs_string_t data = iotjs_string_create(); + iotjs_string_t signature = iotjs_string_create(); + + if ((!iotjs_jbuffer_as_string(jkey, &key)) || + (!iotjs_jbuffer_as_string(jdata, &data)) || + (!iotjs_jbuffer_as_string(jsignature, &signature))) { + iotjs_string_destroy(&key); + iotjs_string_destroy(&data); + iotjs_string_destroy(&signature); + + return jerry_create_boolean(false); + } + + mbedtls_pk_context pk; + + char *raw_signature = NULL; + size_t raw_signature_sz = + iotjs_base64_decode(&raw_signature, iotjs_string_data(&signature), + iotjs_string_size(&signature)); + mbedtls_pk_init(&pk); + int ret_val = + mbedtls_pk_parse_public_key(&pk, (const unsigned char *)iotjs_string_data( + &key), + iotjs_string_size(&key) + 1); + + + jerry_value_t js_ret_val = jerry_create_boolean(true); + if ((ret_val = + mbedtls_pk_verify(&pk, type, + (const unsigned char *)iotjs_string_data(&data), 0, + (const unsigned char *)raw_signature, + raw_signature_sz))) { + js_ret_val = jerry_create_boolean(false); + } + + iotjs_string_destroy(&key); + iotjs_string_destroy(&data); + iotjs_string_destroy(&signature); + mbedtls_pk_free(&pk); + IOTJS_RELEASE(raw_signature); + + return js_ret_val; +#endif /* !ENABLE_MODULE_TLS */ +} + + +JS_FUNCTION(base64_encode) { + DJS_CHECK_THIS(); + + jerry_value_t jstring = JS_GET_ARG(0, any); + iotjs_string_t user_str = iotjs_string_create(); + + if (!iotjs_jbuffer_as_string(jstring, &user_str)) { + return jerry_create_undefined(); + } + + unsigned char *out_buff = NULL; + size_t out_size = + iotjs_base64_encode(&out_buff, + (const unsigned char *)iotjs_string_data(&user_str), + iotjs_string_size(&user_str)); + + iotjs_string_destroy(&user_str); + jerry_value_t ret_val = jerry_create_string_sz(out_buff, out_size); + + IOTJS_RELEASE(out_buff); + return ret_val; +} + + +jerry_value_t iotjs_init_crypto(void) { + jerry_value_t jcrypto = jerry_create_object(); + + iotjs_jval_set_method(jcrypto, IOTJS_MAGIC_STRING_SHAENCODE, sha_encode); + iotjs_jval_set_method(jcrypto, IOTJS_MAGIC_STRING_BASE64ENCODE, + base64_encode); + iotjs_jval_set_method(jcrypto, IOTJS_MAGIC_STRING_RSAVERIFY, rsa_verify); + + return jcrypto; +} diff --git a/src/modules/iotjs_module_crypto.h b/src/modules/iotjs_module_crypto.h new file mode 100644 index 0000000000..380fa54418 --- /dev/null +++ b/src/modules/iotjs_module_crypto.h @@ -0,0 +1,22 @@ +/* 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_CRYPTO_H +#define IOTJS_MODULE_CRYPTO_H + +size_t iotjs_sha1_encode(unsigned char **out_buff, const unsigned char *in_buff, + size_t buff_len); +size_t iotjs_sha256_encode(unsigned char **out_buff, + const unsigned char *in_buff, size_t buff_len); +#endif /* IOTJS_MODULE_CRYPTO_H */ diff --git a/src/modules/iotjs_module_dns.c b/src/modules/iotjs_module_dns.c index 949cbf4989..834ae0eac4 100644 --- a/src/modules/iotjs_module_dns.c +++ b/src/modules/iotjs_module_dns.c @@ -15,111 +15,117 @@ #include "iotjs_def.h" -#include "iotjs_module_dns.h" - -#include "iotjs_reqwrap.h" -#include "uv.h" - - -#define THIS iotjs_getaddrinfo_reqwrap_t* getaddrinfo_reqwrap - -iotjs_getaddrinfo_reqwrap_t* iotjs_getaddrinfo_reqwrap_create( - const iotjs_jval_t* jcallback) { - iotjs_getaddrinfo_reqwrap_t* getaddrinfo_reqwrap = - IOTJS_ALLOC(iotjs_getaddrinfo_reqwrap_t); - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_getaddrinfo_reqwrap_t, - getaddrinfo_reqwrap); - iotjs_reqwrap_initialize(&_this->reqwrap, jcallback, (uv_req_t*)&_this->req); - return getaddrinfo_reqwrap; -} - - -static void iotjs_getaddrinfo_reqwrap_destroy(THIS) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_getaddrinfo_reqwrap_t, - getaddrinfo_reqwrap); - iotjs_reqwrap_destroy(&_this->reqwrap); - IOTJS_RELEASE(getaddrinfo_reqwrap); -} - - -void iotjs_getaddrinfo_reqwrap_dispatched(THIS) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_getaddrinfo_reqwrap_t, - getaddrinfo_reqwrap); - iotjs_getaddrinfo_reqwrap_destroy(getaddrinfo_reqwrap); -} - - -uv_getaddrinfo_t* iotjs_getaddrinfo_reqwrap_req(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_getaddrinfo_reqwrap_t, - getaddrinfo_reqwrap); - return &_this->req; -} - - -const iotjs_jval_t* iotjs_getaddrinfo_reqwrap_jcallback(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_getaddrinfo_reqwrap_t, - getaddrinfo_reqwrap); - return iotjs_reqwrap_jcallback(&_this->reqwrap); +#include "iotjs_uv_request.h" + +#if !defined(__NUTTX__) +char* getaddrinfo_error_str(int status) { + switch (status) { + case UV__EAI_ADDRFAMILY: + return "EAI_ADDRFAMILY, address family for hostname not supported"; + case UV__EAI_AGAIN: + return "EAI_AGAIN, temporary failure in name resolution"; + case UV__EAI_BADFLAGS: + return "EAI_BADFLAGS, bad flags"; + case UV__EAI_FAIL: + return "EAI_FAIL, Non-recoverable failure in name resolution"; + case UV__EAI_FAMILY: + return "EAI_FAMILY, family not supported"; + case UV__EAI_CANCELED: + return "EAI_CANCELED, request canceled"; + case UV__EAI_MEMORY: + return "EAI_MEMORY, memory allocation failure"; + case UV__EAI_NODATA: + return "EAI_NODATA, no address association with hostname"; + case UV__EAI_NONAME: + return "EAI_NONAME, name or service not known"; + case UV__EAI_OVERFLOW: + return "EAI_OVERFLOW, argument buffer overflow"; + case UV__EAI_SERVICE: + return "EAI_SERVICE, service not supported"; + case UV__EAI_SOCKTYPE: + return "EAI_SOCKTYPE, socktype not supported"; + case UV__EAI_PROTOCOL: + return "EAI_PROTOCOL, unknown error"; + default: + return "unknown error"; + } } -#undef THIS - - -#if !defined(__NUTTX__) && !defined(__TIZENRT__) -static void AfterGetAddrInfo(uv_getaddrinfo_t* req, int status, - struct addrinfo* res) { - iotjs_getaddrinfo_reqwrap_t* req_wrap = - (iotjs_getaddrinfo_reqwrap_t*)(req->data); +static void after_get_addr_info(uv_getaddrinfo_t* req, int status, + struct addrinfo* res) { + size_t argc = 0; + jerry_value_t args[3] = { 0 }; - iotjs_jargs_t args = iotjs_jargs_create(3); - iotjs_jargs_append_number(&args, status); - - if (status == 0) { + if (status == 0 && res != NULL) { char ip[INET6_ADDRSTRLEN]; int family; const char* addr; + struct addrinfo* info; + + /* search for the first AF_INET entry */ + for (info = res; info != NULL; info = info->ai_next) { + if (info->ai_family == AF_INET) { + break; + } + } + + if (info == NULL) { + /* Did not find an AF_INET addr, using the first one */ + info = res; + } - // Only first address is used - if (res->ai_family == AF_INET) { - struct sockaddr_in* sockaddr = (struct sockaddr_in*)(res->ai_addr); + IOTJS_ASSERT(info != NULL); + + if (info->ai_family == AF_INET) { + struct sockaddr_in* sockaddr = (struct sockaddr_in*)(info->ai_addr); addr = (char*)(&(sockaddr->sin_addr)); family = 4; } else { - struct sockaddr_in6* sockaddr = (struct sockaddr_in6*)(res->ai_addr); + struct sockaddr_in6* sockaddr = (struct sockaddr_in6*)(info->ai_addr); addr = (char*)(&(sockaddr->sin6_addr)); family = 6; } - int err = uv_inet_ntop(res->ai_family, addr, ip, INET6_ADDRSTRLEN); + int err = uv_inet_ntop(info->ai_family, addr, ip, INET6_ADDRSTRLEN); if (err) { ip[0] = 0; + args[argc++] = iotjs_jval_create_error_without_error_flag( + "EAFNOSUPPORT, DNS could not resolve hostname"); + } else { + args[argc++] = jerry_create_null(); } - iotjs_jargs_append_string_raw(&args, ip); - iotjs_jargs_append_number(&args, family); + args[argc++] = jerry_create_string_from_utf8((const jerry_char_t*)ip); + args[argc++] = jerry_create_number(family); + } else { + args[argc++] = iotjs_jval_create_error_without_error_flag( + getaddrinfo_error_str(status)); } uv_freeaddrinfo(res); // Make the callback into JavaScript - iotjs_make_callback(iotjs_getaddrinfo_reqwrap_jcallback(req_wrap), - iotjs_jval_get_undefined(), &args); + jerry_value_t jcallback = *IOTJS_UV_REQUEST_JSCALLBACK(req); + iotjs_invoke_callback(jcallback, jerry_create_undefined(), args, argc); - iotjs_jargs_destroy(&args); + for (size_t i = 0; i < argc; i++) { + jerry_release_value(args[i]); + } - iotjs_getaddrinfo_reqwrap_dispatched(req_wrap); + iotjs_uv_request_destroy((uv_req_t*)req); } #endif -JHANDLER_FUNCTION(GetAddrInfo) { - DJHANDLER_CHECK_THIS(object); - DJHANDLER_CHECK_ARGS(4, string, number, number, function); +JS_FUNCTION(get_address_info) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(4, string, number, number, function); - iotjs_string_t hostname = JHANDLER_GET_ARG(0, string); - int option = JHANDLER_GET_ARG(1, number); - int flags = JHANDLER_GET_ARG(2, number); - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG(3, function); + iotjs_string_t hostname = JS_GET_ARG(0, string); + int option = JS_GET_ARG(1, number); + int flags = JS_GET_ARG(2, number); + int error = 0; + const jerry_value_t jcallback = JS_GET_ARG(3, function); int family; if (option == 0) { @@ -133,39 +139,47 @@ JHANDLER_FUNCTION(GetAddrInfo) { } else if (option == 6) { family = AF_INET6; } else { - JHANDLER_THROW(TYPE, "bad address family"); - return; + iotjs_string_destroy(&hostname); + return JS_CREATE_ERROR(TYPE, "bad address family"); } -#if defined(__NUTTX__) || defined(__TIZENRT__) - iotjs_jargs_t args = iotjs_jargs_create(3); - int err = 0; - char ip[INET6_ADDRSTRLEN]; +#if defined(__NUTTX__) + char ip[INET6_ADDRSTRLEN] = ""; const char* hostname_data = iotjs_string_data(&hostname); if (strcmp(hostname_data, "localhost") == 0) { - strcpy(ip, "127.0.0.1"); + strncpy(ip, "127.0.0.1", strlen("127.0.0.1") + 1); } else { struct sockaddr_in addr; - int result = inet_pton(family, hostname_data, &(addr.sin_addr)); - if (result != 1) { - err = errno; - } else { + if (inet_pton(family, hostname_data, &(addr.sin_addr)) == 1) { inet_ntop(family, &(addr.sin_addr), ip, INET6_ADDRSTRLEN); + } else { + error = EAFNOSUPPORT; } } - iotjs_jargs_append_number(&args, err); - iotjs_jargs_append_string_raw(&args, ip); - iotjs_jargs_append_number(&args, option); + size_t argc = 0; + jerry_value_t args[3] = { 0 }; - iotjs_make_callback(jcallback, iotjs_jval_get_undefined(), &args); - iotjs_jargs_destroy(&args); + if (error) { + args[argc++] = iotjs_jval_create_error_without_error_flag( + "EAFNOSUPPORT, could not resolve hostname"); + } else { + args[argc++] = jerry_create_null(); + } + + args[argc++] = jerry_create_string_from_utf8((const jerry_char_t*)ip); + args[argc++] = jerry_create_number(option); + + iotjs_invoke_callback(jcallback, jerry_create_undefined(), args, argc); + for (size_t i = 0; i < argc; i++) { + jerry_release_value(args[i]); + } IOTJS_UNUSED(flags); #else - iotjs_getaddrinfo_reqwrap_t* req_wrap = - iotjs_getaddrinfo_reqwrap_create(jcallback); + uv_req_t* req_addr = + iotjs_uv_request_create(sizeof(uv_getaddrinfo_t), jcallback, 0); static const struct addrinfo empty_hints; struct addrinfo hints = empty_hints; @@ -173,19 +187,19 @@ JHANDLER_FUNCTION(GetAddrInfo) { hints.ai_socktype = SOCK_STREAM; hints.ai_flags = flags; - int err = - uv_getaddrinfo(iotjs_environment_loop(iotjs_environment_get()), - iotjs_getaddrinfo_reqwrap_req(req_wrap), AfterGetAddrInfo, - iotjs_string_data(&hostname), NULL, &hints); + error = uv_getaddrinfo(iotjs_environment_loop(iotjs_environment_get()), + (uv_getaddrinfo_t*)req_addr, after_get_addr_info, + iotjs_string_data(&hostname), NULL, &hints); - if (err) { - iotjs_getaddrinfo_reqwrap_dispatched(req_wrap); + if (error) { + iotjs_uv_request_destroy(req_addr); } #endif - iotjs_jhandler_return_number(jhandler, err); iotjs_string_destroy(&hostname); + + return jerry_create_number(error); } @@ -195,12 +209,12 @@ JHANDLER_FUNCTION(GetAddrInfo) { } while (0) -iotjs_jval_t InitDns() { - iotjs_jval_t dns = iotjs_jval_create_object(); +jerry_value_t iotjs_init_dns(void) { + jerry_value_t dns = jerry_create_object(); - iotjs_jval_set_method(&dns, IOTJS_MAGIC_STRING_GETADDRINFO, GetAddrInfo); - SET_CONSTANT(&dns, AI_ADDRCONFIG); - SET_CONSTANT(&dns, AI_V4MAPPED); + iotjs_jval_set_method(dns, IOTJS_MAGIC_STRING_GETADDRINFO, get_address_info); + SET_CONSTANT(dns, AI_ADDRCONFIG); + SET_CONSTANT(dns, AI_V4MAPPED); return dns; } diff --git a/src/modules/iotjs_module_dns.h b/src/modules/iotjs_module_dns.h deleted file mode 100644 index 51cc50896b..0000000000 --- a/src/modules/iotjs_module_dns.h +++ /dev/null @@ -1,43 +0,0 @@ -/* Copyright 2015-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_DNS_H -#define IOTJS_MODULE_DNS_H - - -#include "iotjs_def.h" -#include "iotjs_reqwrap.h" - - -typedef struct { - iotjs_reqwrap_t reqwrap; - uv_getaddrinfo_t req; -} IOTJS_VALIDATED_STRUCT(iotjs_getaddrinfo_reqwrap_t); - -#define THIS iotjs_getaddrinfo_reqwrap_t* getaddrinfo_reqwrap - -iotjs_getaddrinfo_reqwrap_t* iotjs_getaddrinfo_reqwrap_create( - const iotjs_jval_t* jcallback); - -void iotjs_getaddrinfo_reqwrap_dispatched(THIS); - -uv_getaddrinfo_t* iotjs_getaddrinfo_reqwrap_req(THIS); -const iotjs_jval_t* iotjs_getaddrinfo_reqwrap_jcallback(THIS); - -#undef THIS - - -#endif /* IOTJS_MODULE_DNS_H */ diff --git a/src/modules/iotjs_module_dynamicloader.c b/src/modules/iotjs_module_dynamicloader.c new file mode 100644 index 0000000000..3916a189b7 --- /dev/null +++ b/src/modules/iotjs_module_dynamicloader.c @@ -0,0 +1,90 @@ +/* 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 "internal/node_api_internal.h" + +#include "iotjs_def.h" + +#if _WIN32 +#include +#else +#include +#endif +#include + +JS_FUNCTION(open_native_module) { + iotjs_string_t location = JS_GET_ARG(0, string); + +#if _WIN32 + // Get a handle to the node module. + HINSTANCE handle = LoadLibrary(iotjs_string_data(&location)); +#else + void* handle = dlopen(iotjs_string_data(&location), RTLD_LAZY); +#endif + iotjs_string_destroy(&location); + + // If the handle is valid, try to get the function address. + if (handle == NULL) { +#if _WIN32 + char* err_msg = ""; + DWORD dw = GetLastError(); + + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &err_msg, + 0, NULL); +#else + char* err_msg = dlerror(); +#endif + jerry_value_t jval_error = + jerry_create_error(JERRY_ERROR_COMMON, (jerry_char_t*)err_msg); + return jval_error; + } + + jerry_value_t exports = jerry_create_undefined(); + + int status = napi_module_init_pending(&exports); + if (status == napi_module_load_ok) { + return exports; + } + + if (status == napi_pending_exception) { +/* exports is an error reference */ +#if _WIN32 + FreeLibrary(handle); +#else + dlclose(handle); +#endif + return exports; + } + + if (status == napi_module_no_nm_register_func) { +#if _WIN32 + FreeLibrary(handle); +#else + dlclose(handle); +#endif + jerry_value_t jval_error = jerry_create_error( + JERRY_ERROR_COMMON, + (jerry_char_t*)"Module has no declared entry point."); + return jval_error; + } + + return exports; +} + +jerry_value_t iotjs_init_dynamicloader(void) { + return jerry_create_external_function(open_native_module); +} diff --git a/src/modules/iotjs_module_fs.c b/src/modules/iotjs_module_fs.c index 0c766529c0..1aa10d39f5 100644 --- a/src/modules/iotjs_module_fs.c +++ b/src/modules/iotjs_module_fs.c @@ -15,67 +15,31 @@ #include "iotjs_def.h" -#include "iotjs_module_fs.h" - #include "iotjs_module_buffer.h" +#include "iotjs_uv_request.h" -#include "iotjs_exception.h" -#include "iotjs_reqwrap.h" - -#undef JHANDLER_FUNCTION -#define JHANDLER_FUNCTION(name) static void name(iotjs_jhandler_t* jhandler) - -iotjs_fs_reqwrap_t* iotjs_fs_reqwrap_create(const iotjs_jval_t* jcallback) { - iotjs_fs_reqwrap_t* fs_reqwrap = IOTJS_ALLOC(iotjs_fs_reqwrap_t); - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_fs_reqwrap_t, fs_reqwrap); - iotjs_reqwrap_initialize(&_this->reqwrap, jcallback, (uv_req_t*)&_this->req); - return fs_reqwrap; -} - - -static void iotjs_fs_reqwrap_destroy(iotjs_fs_reqwrap_t* fs_reqwrap) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_fs_reqwrap_t, fs_reqwrap); - uv_fs_req_cleanup(&_this->req); - iotjs_reqwrap_destroy(&_this->reqwrap); - IOTJS_RELEASE(fs_reqwrap); -} +jerry_value_t make_stat_object(uv_stat_t* statbuf); -void iotjs_fs_reqwrap_dispatched(iotjs_fs_reqwrap_t* fs_reqwrap) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_fs_reqwrap_t, fs_reqwrap); - iotjs_fs_reqwrap_destroy(fs_reqwrap); +static jerry_value_t iotjs_create_uv_exception(int errorno, + const char* syscall) { + static char msg[256]; + snprintf(msg, sizeof(msg), "'%s' %s", syscall, uv_strerror(errorno)); + return iotjs_jval_create_error_without_error_flag(msg); } -uv_fs_t* iotjs_fs_reqwrap_req(iotjs_fs_reqwrap_t* fs_reqwrap) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_fs_reqwrap_t, fs_reqwrap); - return &_this->req; -} - -const iotjs_jval_t* iotjs_fs_reqwrap_jcallback(iotjs_fs_reqwrap_t* fs_reqwrap) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_fs_reqwrap_t, fs_reqwrap); - return iotjs_reqwrap_jcallback(&_this->reqwrap); -} +static void fs_after_async(uv_fs_t* req) { + const jerry_value_t cb = *IOTJS_UV_REQUEST_JSCALLBACK(req); + IOTJS_ASSERT(jerry_value_is_function(cb)); - -iotjs_jval_t MakeStatObject(uv_stat_t* statbuf); - - -static void AfterAsync(uv_fs_t* req) { - iotjs_fs_reqwrap_t* req_wrap = (iotjs_fs_reqwrap_t*)(req->data); - IOTJS_ASSERT(req_wrap != NULL); - IOTJS_ASSERT(iotjs_fs_reqwrap_req(req_wrap) == req); - - const iotjs_jval_t* cb = iotjs_fs_reqwrap_jcallback(req_wrap); - IOTJS_ASSERT(iotjs_jval_is_function(cb)); - - iotjs_jargs_t jarg = iotjs_jargs_create(2); + jerry_value_t jargs[2] = { 0 }; + size_t jargc = 0; if (req->result < 0) { - iotjs_jval_t jerror = iotjs_create_uv_exception(req->result, "open"); - iotjs_jargs_append_jval(&jarg, &jerror); - iotjs_jval_destroy(&jerror); + jerry_value_t jerror = iotjs_create_uv_exception(req->result, "open"); + jargs[jargc++] = jerror; } else { - iotjs_jargs_append_null(&jarg); + jargs[jargc++] = jerry_create_null(); switch (req->fs_type) { case UV_FS_CLOSE: { break; @@ -83,441 +47,458 @@ static void AfterAsync(uv_fs_t* req) { case UV_FS_OPEN: case UV_FS_READ: case UV_FS_WRITE: { - iotjs_jargs_append_number(&jarg, (double)req->result); + jargs[jargc++] = jerry_create_number((double)req->result); break; } case UV_FS_SCANDIR: { int r; uv_dirent_t ent; uint32_t idx = 0; - iotjs_jval_t ret = iotjs_jval_create_array(0); + jargs[jargc++] = jerry_create_array(0); while ((r = uv_fs_scandir_next(req, &ent)) != UV_EOF) { - iotjs_jval_t name = iotjs_jval_create_string_raw(ent.name); - iotjs_jval_set_property_by_index(&ret, idx, &name); - iotjs_jval_destroy(&name); + jerry_value_t name = + jerry_create_string((const jerry_char_t*)ent.name); + iotjs_jval_set_property_by_index(jargs[1], idx, name); + jerry_release_value(name); idx++; } - iotjs_jargs_append_jval(&jarg, &ret); - iotjs_jval_destroy(&ret); break; } case UV_FS_FSTAT: case UV_FS_STAT: { uv_stat_t s = (req->statbuf); - iotjs_jval_t ret = MakeStatObject(&s); - iotjs_jargs_append_jval(&jarg, &ret); - iotjs_jval_destroy(&ret); - break; - } - default: { - iotjs_jargs_append_null(&jarg); + jargs[jargc++] = make_stat_object(&s); break; } + default: { break; } } } - iotjs_make_callback(cb, iotjs_jval_get_undefined(), &jarg); + iotjs_invoke_callback(cb, jerry_create_undefined(), jargs, jargc); - iotjs_jargs_destroy(&jarg); - iotjs_fs_reqwrap_dispatched(req_wrap); + jerry_release_value(jargs[0]); + jerry_release_value(jargs[1]); + uv_fs_req_cleanup(req); + iotjs_uv_request_destroy((uv_req_t*)req); } -static void AfterSync(uv_fs_t* req, int err, const char* syscall_name, - iotjs_jhandler_t* jhandler) { +static jerry_value_t fs_after_sync(uv_fs_t* req, int err, + const char* syscall_name) { if (err < 0) { - iotjs_jval_t jerror = iotjs_create_uv_exception(err, syscall_name); - iotjs_jhandler_throw(jhandler, &jerror); - iotjs_jval_destroy(&jerror); - } else { - switch (req->fs_type) { - case UV_FS_CLOSE: - break; - case UV_FS_OPEN: - case UV_FS_READ: - case UV_FS_WRITE: - iotjs_jhandler_return_number(jhandler, err); - break; - case UV_FS_FSTAT: - case UV_FS_STAT: { - uv_stat_t* s = &(req->statbuf); - iotjs_jval_t stat = MakeStatObject(s); - iotjs_jhandler_return_jval(jhandler, &stat); - iotjs_jval_destroy(&stat); - break; - } - case UV_FS_MKDIR: - case UV_FS_RMDIR: - case UV_FS_UNLINK: - case UV_FS_RENAME: - iotjs_jhandler_return_undefined(jhandler); - break; - case UV_FS_SCANDIR: { - int r; - uv_dirent_t ent; - uint32_t idx = 0; - iotjs_jval_t ret = iotjs_jval_create_array(0); - while ((r = uv_fs_scandir_next(req, &ent)) != UV_EOF) { - iotjs_jval_t name = iotjs_jval_create_string_raw(ent.name); - iotjs_jval_set_property_by_index(&ret, idx, &name); - iotjs_jval_destroy(&name); - idx++; - } - iotjs_jhandler_return_jval(jhandler, &ret); - iotjs_jval_destroy(&ret); - break; - } - default: { - IOTJS_ASSERT(false); - break; + jerry_value_t jvalue = iotjs_create_uv_exception(err, syscall_name); + jerry_value_t jerror = jerry_create_error_from_value(jvalue, true); + return jerror; + } + + switch (req->fs_type) { + case UV_FS_CLOSE: + break; + case UV_FS_OPEN: + case UV_FS_READ: + case UV_FS_WRITE: + return jerry_create_number(err); + case UV_FS_FSTAT: + case UV_FS_STAT: { + uv_stat_t* s = &(req->statbuf); + return make_stat_object(s); + } + case UV_FS_MKDIR: + case UV_FS_RMDIR: + case UV_FS_UNLINK: + case UV_FS_RENAME: + return jerry_create_undefined(); + case UV_FS_SCANDIR: { + int r; + uv_dirent_t ent; + uint32_t idx = 0; + jerry_value_t ret = jerry_create_array(0); + while ((r = uv_fs_scandir_next(req, &ent)) != UV_EOF) { + jerry_value_t name = jerry_create_string((const jerry_char_t*)ent.name); + iotjs_jval_set_property_by_index(ret, idx, name); + jerry_release_value(name); + idx++; } + return ret; + } + default: { + IOTJS_ASSERT(false); + break; } } + return jerry_create_undefined(); } -static inline bool IsWithinBounds(size_t off, size_t len, size_t max) { - if (off > max) - return false; - - if (max - off < len) +static inline bool is_within_bounds(size_t off, size_t len, size_t max) { + if (off >= max || max - off < len) return false; return true; } + #define FS_ASYNC(env, syscall, pcallback, ...) \ - iotjs_fs_reqwrap_t* req_wrap = iotjs_fs_reqwrap_create(pcallback); \ - uv_fs_t* fs_req = iotjs_fs_reqwrap_req(req_wrap); \ + uv_fs_t* fs_req = \ + (uv_fs_t*)iotjs_uv_request_create(sizeof(uv_fs_t), pcallback, 0); \ int err = uv_fs_##syscall(iotjs_environment_loop(env), fs_req, __VA_ARGS__, \ - AfterAsync); \ + fs_after_async); \ if (err < 0) { \ fs_req->result = err; \ - AfterAsync(fs_req); \ + fs_after_async(fs_req); \ } \ - iotjs_jhandler_return_null(jhandler); + ret_value = jerry_create_null(); #define FS_SYNC(env, syscall, ...) \ uv_fs_t fs_req; \ int err = uv_fs_##syscall(iotjs_environment_loop(env), &fs_req, __VA_ARGS__, \ NULL); \ - AfterSync(&fs_req, err, #syscall, jhandler); \ + ret_value = fs_after_sync(&fs_req, err, #syscall); \ uv_fs_req_cleanup(&fs_req); -JHANDLER_FUNCTION(Close) { - DJHANDLER_CHECK_THIS(object); - DJHANDLER_CHECK_ARGS(1, number); - DJHANDLER_CHECK_ARG_IF_EXIST(1, function); +JS_FUNCTION(fs_close) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(1, number); + DJS_CHECK_ARG_IF_EXIST(1, function); const iotjs_environment_t* env = iotjs_environment_get(); - int fd = JHANDLER_GET_ARG(0, number); - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(1, function); + int fd = JS_GET_ARG(0, number); + const jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(1, function); - if (jcallback) { + jerry_value_t ret_value; + if (!jerry_value_is_null(jcallback)) { FS_ASYNC(env, close, jcallback, fd); } else { FS_SYNC(env, close, fd); } + return ret_value; } -JHANDLER_FUNCTION(Open) { - DJHANDLER_CHECK_THIS(object); - DJHANDLER_CHECK_ARGS(3, string, number, number); - DJHANDLER_CHECK_ARG_IF_EXIST(3, function); +JS_FUNCTION(fs_open) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(3, string, number, number); + DJS_CHECK_ARG_IF_EXIST(3, function); const iotjs_environment_t* env = iotjs_environment_get(); - iotjs_string_t path = JHANDLER_GET_ARG(0, string); - int flags = JHANDLER_GET_ARG(1, number); - int mode = JHANDLER_GET_ARG(2, number); - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(3, function); + iotjs_string_t path = JS_GET_ARG(0, string); + int flags = JS_GET_ARG(1, number); + int mode = JS_GET_ARG(2, number); + const jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(3, function); - if (jcallback) { + jerry_value_t ret_value; + if (!jerry_value_is_null(jcallback)) { FS_ASYNC(env, open, jcallback, iotjs_string_data(&path), flags, mode); } else { FS_SYNC(env, open, iotjs_string_data(&path), flags, mode); } iotjs_string_destroy(&path); + return ret_value; } -JHANDLER_FUNCTION(Read) { - DJHANDLER_CHECK_THIS(object); - DJHANDLER_CHECK_ARGS(5, number, object, number, number, number); - DJHANDLER_CHECK_ARG_IF_EXIST(5, function); +typedef enum { IOTJS_FS_READ, IOTJS_FS_WRITE } iotjs_fs_op_t; + +jerry_value_t fs_do_read_or_write(const jerry_value_t jfunc, + const jerry_value_t jthis, + const jerry_value_t jargv[], + const jerry_length_t jargc, + const iotjs_fs_op_t fs_op) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(5, number, object, number, number, number); + DJS_CHECK_ARG_IF_EXIST(5, function); const iotjs_environment_t* env = iotjs_environment_get(); - int fd = JHANDLER_GET_ARG(0, number); - const iotjs_jval_t* jbuffer = JHANDLER_GET_ARG(1, object); - size_t offset = JHANDLER_GET_ARG(2, number); - size_t length = JHANDLER_GET_ARG(3, number); - int position = JHANDLER_GET_ARG(4, number); - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(5, function); + int fd = JS_GET_ARG(0, number); + const jerry_value_t jbuffer = JS_GET_ARG(1, object); + size_t offset = JS_GET_ARG(2, number); + size_t length = JS_GET_ARG(3, number); + int position = JS_GET_ARG(4, number); + const jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(5, function); iotjs_bufferwrap_t* buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuffer); - char* data = iotjs_bufferwrap_buffer(buffer_wrap); + char* data = buffer_wrap->buffer; size_t data_length = iotjs_bufferwrap_length(buffer_wrap); - JHANDLER_CHECK(data != NULL); - JHANDLER_CHECK(data_length > 0); + DJS_CHECK(data != NULL && data_length > 0); - if (offset >= data_length) { - JHANDLER_THROW(RANGE, "offset out of bound"); - return; - } - if (!IsWithinBounds(offset, length, data_length)) { - JHANDLER_THROW(RANGE, "length out of bound"); - return; + if (!is_within_bounds(offset, length, data_length)) { + return JS_CREATE_ERROR(RANGE, "length out of bound"); } uv_buf_t uvbuf = uv_buf_init(data + offset, length); - if (jcallback) { - FS_ASYNC(env, read, jcallback, fd, &uvbuf, 1, position); + jerry_value_t ret_value; + if (fs_op == IOTJS_FS_READ) { + if (!jerry_value_is_null(jcallback)) { + FS_ASYNC(env, read, jcallback, fd, &uvbuf, 1, position); + } else { + FS_SYNC(env, read, fd, &uvbuf, 1, position); + } } else { - FS_SYNC(env, read, fd, &uvbuf, 1, position); + if (!jerry_value_is_null(jcallback)) { + FS_ASYNC(env, write, jcallback, fd, &uvbuf, 1, position); + } else { + FS_SYNC(env, write, fd, &uvbuf, 1, position); + } } + return ret_value; } -JHANDLER_FUNCTION(Write) { - DJHANDLER_CHECK_THIS(object); - DJHANDLER_CHECK_ARGS(5, number, object, number, number, number); - DJHANDLER_CHECK_ARG_IF_EXIST(5, function); - - const iotjs_environment_t* env = iotjs_environment_get(); +JS_FUNCTION(fs_read) { + return fs_do_read_or_write(jfunc, jthis, jargv, jargc, IOTJS_FS_READ); +} - int fd = JHANDLER_GET_ARG(0, number); - const iotjs_jval_t* jbuffer = JHANDLER_GET_ARG(1, object); - size_t offset = JHANDLER_GET_ARG(2, number); - size_t length = JHANDLER_GET_ARG(3, number); - int position = JHANDLER_GET_ARG(4, number); - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(5, function); - iotjs_bufferwrap_t* buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuffer); - char* data = iotjs_bufferwrap_buffer(buffer_wrap); - size_t data_length = iotjs_bufferwrap_length(buffer_wrap); - JHANDLER_CHECK(data != NULL); - JHANDLER_CHECK(data_length > 0); - - if (offset >= data_length) { - JHANDLER_THROW(RANGE, "offset out of bound"); - return; - } - if (!IsWithinBounds(offset, length, data_length)) { - JHANDLER_THROW(RANGE, "length out of bound"); - return; - } +JS_FUNCTION(fs_write) { + return fs_do_read_or_write(jfunc, jthis, jargv, jargc, IOTJS_FS_WRITE); +} - uv_buf_t uvbuf = uv_buf_init(data + offset, length); - if (jcallback) { - FS_ASYNC(env, write, jcallback, fd, &uvbuf, 1, position); - } else { - FS_SYNC(env, write, fd, &uvbuf, 1, position); - } -} +jerry_value_t make_stat_object(uv_stat_t* statbuf) { + const jerry_value_t fs = iotjs_module_get("fs"); + jerry_value_t stat_prototype = + iotjs_jval_get_property(fs, IOTJS_MAGIC_STRING_STATS); + IOTJS_ASSERT(jerry_value_is_object(stat_prototype)); -iotjs_jval_t MakeStatObject(uv_stat_t* statbuf) { - const iotjs_jval_t* fs = iotjs_module_get(MODULE_FS); + jerry_value_t jstat = jerry_create_object(); + iotjs_jval_set_prototype(jstat, stat_prototype); - iotjs_jval_t create_stat = - iotjs_jval_get_property(fs, IOTJS_MAGIC_STRING__CREATESTAT); - IOTJS_ASSERT(iotjs_jval_is_function(&create_stat)); + jerry_release_value(stat_prototype); - iotjs_jval_t jstat = iotjs_jval_create_object(); #define X(statobj, name) \ iotjs_jval_set_property_number(statobj, #name, statbuf->st_##name); - X(&jstat, dev) - X(&jstat, mode) - X(&jstat, nlink) - X(&jstat, uid) - X(&jstat, gid) - X(&jstat, rdev) - X(&jstat, blksize) - X(&jstat, ino) - X(&jstat, size) - X(&jstat, blocks) + X(jstat, dev) + X(jstat, mode) + X(jstat, nlink) + X(jstat, uid) + X(jstat, gid) + X(jstat, rdev) + X(jstat, blksize) + X(jstat, ino) + X(jstat, size) + X(jstat, blocks) #undef X - iotjs_jargs_t jargs = iotjs_jargs_create(1); - iotjs_jargs_append_jval(&jargs, &jstat); - iotjs_jval_destroy(&jstat); - - iotjs_jval_t res = - iotjs_jhelper_call_ok(&create_stat, iotjs_jval_get_undefined(), &jargs); - - iotjs_jargs_destroy(&jargs); - iotjs_jval_destroy(&create_stat); - - return res; + return jstat; } -JHANDLER_FUNCTION(Stat) { - DJHANDLER_CHECK_THIS(object); - DJHANDLER_CHECK_ARGS(1, string); - DJHANDLER_CHECK_ARG_IF_EXIST(1, function); +JS_FUNCTION(fs_stat) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(1, string); + DJS_CHECK_ARG_IF_EXIST(1, function); const iotjs_environment_t* env = iotjs_environment_get(); - iotjs_string_t path = JHANDLER_GET_ARG(0, string); - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(1, function); + iotjs_string_t path = JS_GET_ARG(0, string); + const jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(1, function); - if (jcallback) { + jerry_value_t ret_value; + if (!jerry_value_is_null(jcallback)) { FS_ASYNC(env, stat, jcallback, iotjs_string_data(&path)); } else { FS_SYNC(env, stat, iotjs_string_data(&path)); } iotjs_string_destroy(&path); + return ret_value; } -JHANDLER_FUNCTION(Fstat) { - DJHANDLER_CHECK_THIS(object); - DJHANDLER_CHECK_ARGS(1, number); - DJHANDLER_CHECK_ARG_IF_EXIST(1, function); +JS_FUNCTION(fs_fstat) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(1, number); + DJS_CHECK_ARG_IF_EXIST(1, function); const iotjs_environment_t* env = iotjs_environment_get(); - int fd = JHANDLER_GET_ARG(0, number); - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(1, function); + int fd = JS_GET_ARG(0, number); + const jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(1, function); - if (jcallback) { + jerry_value_t ret_value; + if (!jerry_value_is_null(jcallback)) { FS_ASYNC(env, fstat, jcallback, fd); } else { FS_SYNC(env, fstat, fd); } + return ret_value; } -JHANDLER_FUNCTION(MkDir) { - DJHANDLER_CHECK_THIS(object); - DJHANDLER_CHECK_ARGS(2, string, number); - DJHANDLER_CHECK_ARG_IF_EXIST(2, function); +JS_FUNCTION(fs_mkdir) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(2, string, number); + DJS_CHECK_ARG_IF_EXIST(2, function); const iotjs_environment_t* env = iotjs_environment_get(); - iotjs_string_t path = JHANDLER_GET_ARG(0, string); - int mode = JHANDLER_GET_ARG(1, number); - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(2, function); + iotjs_string_t path = JS_GET_ARG(0, string); + int mode = JS_GET_ARG(1, number); + const jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(2, function); - if (jcallback) { + jerry_value_t ret_value; + if (!jerry_value_is_null(jcallback)) { FS_ASYNC(env, mkdir, jcallback, iotjs_string_data(&path), mode); } else { FS_SYNC(env, mkdir, iotjs_string_data(&path), mode); } iotjs_string_destroy(&path); + return ret_value; } -JHANDLER_FUNCTION(RmDir) { - DJHANDLER_CHECK_THIS(object); - DJHANDLER_CHECK_ARGS(1, string); - DJHANDLER_CHECK_ARG_IF_EXIST(1, function); +JS_FUNCTION(fs_rmdir) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(1, string); + DJS_CHECK_ARG_IF_EXIST(1, function); const iotjs_environment_t* env = iotjs_environment_get(); - iotjs_string_t path = JHANDLER_GET_ARG(0, string); - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(1, function); + iotjs_string_t path = JS_GET_ARG(0, string); + const jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(1, function); - if (jcallback) { + jerry_value_t ret_value; + if (!jerry_value_is_null(jcallback)) { FS_ASYNC(env, rmdir, jcallback, iotjs_string_data(&path)); } else { FS_SYNC(env, rmdir, iotjs_string_data(&path)); } iotjs_string_destroy(&path); + return ret_value; } -JHANDLER_FUNCTION(Unlink) { - DJHANDLER_CHECK_THIS(object); - DJHANDLER_CHECK_ARGS(1, string); - DJHANDLER_CHECK_ARG_IF_EXIST(1, function); +JS_FUNCTION(fs_unlink) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(1, string); + DJS_CHECK_ARG_IF_EXIST(1, function); const iotjs_environment_t* env = iotjs_environment_get(); - iotjs_string_t path = JHANDLER_GET_ARG(0, string); - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(1, function); + iotjs_string_t path = JS_GET_ARG(0, string); + const jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(1, function); - if (jcallback) { + jerry_value_t ret_value; + if (!jerry_value_is_null(jcallback)) { FS_ASYNC(env, unlink, jcallback, iotjs_string_data(&path)); } else { FS_SYNC(env, unlink, iotjs_string_data(&path)); } iotjs_string_destroy(&path); + return ret_value; } -JHANDLER_FUNCTION(Rename) { - DJHANDLER_CHECK_THIS(object); - DJHANDLER_CHECK_ARGS(2, string, string); - DJHANDLER_CHECK_ARG_IF_EXIST(2, function); +JS_FUNCTION(fs_rename) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(2, string, string); + DJS_CHECK_ARG_IF_EXIST(2, function); const iotjs_environment_t* env = iotjs_environment_get(); - iotjs_string_t oldPath = JHANDLER_GET_ARG(0, string); - iotjs_string_t newPath = JHANDLER_GET_ARG(1, string); - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(2, function); + iotjs_string_t old_path = JS_GET_ARG(0, string); + iotjs_string_t new_path = JS_GET_ARG(1, string); + const jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(2, function); - if (jcallback) { - FS_ASYNC(env, rename, jcallback, iotjs_string_data(&oldPath), - iotjs_string_data(&newPath)); + jerry_value_t ret_value; + if (!jerry_value_is_null(jcallback)) { + FS_ASYNC(env, rename, jcallback, iotjs_string_data(&old_path), + iotjs_string_data(&new_path)); } else { - FS_SYNC(env, rename, iotjs_string_data(&oldPath), - iotjs_string_data(&newPath)); + FS_SYNC(env, rename, iotjs_string_data(&old_path), + iotjs_string_data(&new_path)); } - iotjs_string_destroy(&oldPath); - iotjs_string_destroy(&newPath); + iotjs_string_destroy(&old_path); + iotjs_string_destroy(&new_path); + return ret_value; } -JHANDLER_FUNCTION(ReadDir) { - DJHANDLER_CHECK_THIS(object); - DJHANDLER_CHECK_ARGS(1, string); - DJHANDLER_CHECK_ARG_IF_EXIST(1, function); +JS_FUNCTION(fs_read_dir) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(1, string); + DJS_CHECK_ARG_IF_EXIST(1, function); const iotjs_environment_t* env = iotjs_environment_get(); - iotjs_string_t path = JHANDLER_GET_ARG(0, string); - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(1, function); + iotjs_string_t path = JS_GET_ARG(0, string); + const jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(1, function); - if (jcallback) { + jerry_value_t ret_value; + if (!jerry_value_is_null(jcallback)) { FS_ASYNC(env, scandir, jcallback, iotjs_string_data(&path), 0); } else { FS_SYNC(env, scandir, iotjs_string_data(&path), 0); } iotjs_string_destroy(&path); + return ret_value; +} + +static jerry_value_t stats_is_typeof(jerry_value_t stats, int type) { + jerry_value_t mode = iotjs_jval_get_property(stats, IOTJS_MAGIC_STRING_MODE); + + if (!jerry_value_is_number(mode)) { + jerry_release_value(mode); + return JS_CREATE_ERROR(TYPE, "fstat: file mode should be a number"); + } + + int mode_number = (int)iotjs_jval_as_number(mode); + + jerry_release_value(mode); + + return jerry_create_boolean((mode_number & S_IFMT) == type); +} + +JS_FUNCTION(fs_stats_is_directory) { + DJS_CHECK_THIS(); + jerry_value_t stats = JS_GET_THIS(); + return stats_is_typeof(stats, S_IFDIR); } +JS_FUNCTION(fs_stats_is_file) { + DJS_CHECK_THIS(); + jerry_value_t stats = JS_GET_THIS(); + return stats_is_typeof(stats, S_IFREG); +} -iotjs_jval_t InitFs() { - iotjs_jval_t fs = iotjs_jval_create_object(); - - iotjs_jval_set_method(&fs, IOTJS_MAGIC_STRING_CLOSE, Close); - iotjs_jval_set_method(&fs, IOTJS_MAGIC_STRING_OPEN, Open); - iotjs_jval_set_method(&fs, IOTJS_MAGIC_STRING_READ, Read); - iotjs_jval_set_method(&fs, IOTJS_MAGIC_STRING_WRITE, Write); - iotjs_jval_set_method(&fs, IOTJS_MAGIC_STRING_STAT, Stat); - iotjs_jval_set_method(&fs, IOTJS_MAGIC_STRING_FSTAT, Fstat); - iotjs_jval_set_method(&fs, IOTJS_MAGIC_STRING_MKDIR, MkDir); - iotjs_jval_set_method(&fs, IOTJS_MAGIC_STRING_RMDIR, RmDir); - iotjs_jval_set_method(&fs, IOTJS_MAGIC_STRING_UNLINK, Unlink); - iotjs_jval_set_method(&fs, IOTJS_MAGIC_STRING_RENAME, Rename); - iotjs_jval_set_method(&fs, IOTJS_MAGIC_STRING_READDIR, ReadDir); +jerry_value_t iotjs_init_fs(void) { + jerry_value_t fs = jerry_create_object(); + + iotjs_jval_set_method(fs, IOTJS_MAGIC_STRING_CLOSE, fs_close); + iotjs_jval_set_method(fs, IOTJS_MAGIC_STRING_OPEN, fs_open); + iotjs_jval_set_method(fs, IOTJS_MAGIC_STRING_READ, fs_read); + iotjs_jval_set_method(fs, IOTJS_MAGIC_STRING_WRITE, fs_write); + iotjs_jval_set_method(fs, IOTJS_MAGIC_STRING_STAT, fs_stat); + iotjs_jval_set_method(fs, IOTJS_MAGIC_STRING_FSTAT, fs_fstat); + iotjs_jval_set_method(fs, IOTJS_MAGIC_STRING_MKDIR, fs_mkdir); + iotjs_jval_set_method(fs, IOTJS_MAGIC_STRING_RMDIR, fs_rmdir); + iotjs_jval_set_method(fs, IOTJS_MAGIC_STRING_UNLINK, fs_unlink); + iotjs_jval_set_method(fs, IOTJS_MAGIC_STRING_RENAME, fs_rename); + iotjs_jval_set_method(fs, IOTJS_MAGIC_STRING_READDIR, fs_read_dir); + + jerry_value_t stats_prototype = jerry_create_object(); + + iotjs_jval_set_method(stats_prototype, IOTJS_MAGIC_STRING_ISDIRECTORY, + fs_stats_is_directory); + iotjs_jval_set_method(stats_prototype, IOTJS_MAGIC_STRING_ISFILE, + fs_stats_is_file); + + iotjs_jval_set_property_jval(fs, IOTJS_MAGIC_STRING_STATS, stats_prototype); + jerry_release_value(stats_prototype); return fs; } diff --git a/src/modules/iotjs_module_gpio.c b/src/modules/iotjs_module_gpio.c index 217998e581..d3030b869a 100644 --- a/src/modules/iotjs_module_gpio.c +++ b/src/modules/iotjs_module_gpio.c @@ -13,378 +13,338 @@ * limitations under the License. */ -#include - #include "iotjs_def.h" #include "iotjs_module_gpio.h" -#include "iotjs_objectwrap.h" -#include +#include "iotjs_uv_request.h" -static iotjs_gpio_t* iotjs_gpio_instance_from_jval(const iotjs_jval_t* jgpio); IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(gpio); - -static iotjs_gpio_t* iotjs_gpio_create(const iotjs_jval_t* jgpio) { - iotjs_gpio_t* gpio = IOTJS_ALLOC(iotjs_gpio_t); - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_gpio_t, gpio); - iotjs_jobjectwrap_initialize(&_this->jobjectwrap, jgpio, - &this_module_native_info); -#if defined(__linux__) - _this->value_fd = -1; -#endif - return gpio; -} - +IOTJS_DEFINE_PERIPH_CREATE_FUNCTION(gpio); static void iotjs_gpio_destroy(iotjs_gpio_t* gpio) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_gpio_t, gpio); - iotjs_jobjectwrap_destroy(&_this->jobjectwrap); + iotjs_gpio_destroy_platform_data(gpio->platform_data); IOTJS_RELEASE(gpio); } - -#define THIS iotjs_gpio_reqwrap_t* gpio_reqwrap - - -static iotjs_gpio_reqwrap_t* iotjs_gpio_reqwrap_create( - const iotjs_jval_t* jcallback, iotjs_gpio_t* gpio, GpioOp op) { - iotjs_gpio_reqwrap_t* gpio_reqwrap = IOTJS_ALLOC(iotjs_gpio_reqwrap_t); - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_gpio_reqwrap_t, gpio_reqwrap); - - iotjs_reqwrap_initialize(&_this->reqwrap, jcallback, (uv_req_t*)&_this->req); - - _this->req_data.op = op; - _this->gpio_instance = gpio; - return gpio_reqwrap; -} - - -static void iotjs_gpio_reqwrap_destroy(THIS) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_gpio_reqwrap_t, gpio_reqwrap); - iotjs_reqwrap_destroy(&_this->reqwrap); - IOTJS_RELEASE(gpio_reqwrap); -} - - -static void iotjs_gpio_reqwrap_dispatched(THIS) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_gpio_reqwrap_t, gpio_reqwrap); - iotjs_gpio_reqwrap_destroy(gpio_reqwrap); -} - - -static uv_work_t* iotjs_gpio_reqwrap_req(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_gpio_reqwrap_t, gpio_reqwrap); - return &_this->req; +static void gpio_worker(uv_work_t* work_req) { + iotjs_periph_data_t* worker_data = + (iotjs_periph_data_t*)IOTJS_UV_REQUEST_EXTRA_DATA(work_req); + iotjs_gpio_t* gpio = (iotjs_gpio_t*)worker_data->data; + + switch (worker_data->op) { + case kGpioOpOpen: + worker_data->result = iotjs_gpio_open(gpio); + break; + case kGpioOpWrite: + worker_data->result = iotjs_gpio_write(gpio); + break; + case kGpioOpRead: + worker_data->result = iotjs_gpio_read(gpio); + break; + case kGpioOpClose: + worker_data->result = iotjs_gpio_close(gpio); + break; + default: + IOTJS_ASSERT(!"Invalid Operation"); + } } +static jerry_value_t gpio_set_configuration(iotjs_gpio_t* gpio, + jerry_value_t jconfigurable) { + jerry_value_t jpin = + iotjs_jval_get_property(jconfigurable, IOTJS_MAGIC_STRING_PIN); -static const iotjs_jval_t* iotjs_gpio_reqwrap_jcallback(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_gpio_reqwrap_t, gpio_reqwrap); - return iotjs_reqwrap_jcallback(&_this->reqwrap); -} - + double pin = -1.0; + if (!jerry_value_is_number(jpin) || (pin = iotjs_jval_as_number(jpin)) < 0) { + jerry_release_value(jpin); + return JS_CREATE_ERROR(TYPE, "Bad arguments gpio.pin should be a number"); + } + gpio->pin = (uint32_t)pin; + jerry_release_value(jpin); -static iotjs_gpio_t* iotjs_gpio_instance_from_jval(const iotjs_jval_t* jgpio) { - uintptr_t handle = iotjs_jval_get_object_native_handle(jgpio); - return (iotjs_gpio_t*)handle; -} + // Direction + jerry_value_t jdirection = + iotjs_jval_get_property(jconfigurable, IOTJS_MAGIC_STRING_DIRECTION); + if (jerry_value_is_undefined(jdirection)) { + gpio->direction = kGpioDirectionOut; + } else { + if (jerry_value_is_number(jdirection)) { + gpio->direction = (GpioDirection)iotjs_jval_as_number(jdirection); + } else { + gpio->direction = __kGpioDirectionMax; + } + if (gpio->direction >= __kGpioDirectionMax) { + jerry_release_value(jdirection); + return JS_CREATE_ERROR( + TYPE, "Bad arguments - gpio.direction should be DIRECTION.IN or OUT"); + } + } + jerry_release_value(jdirection); -iotjs_gpio_reqwrap_t* iotjs_gpio_reqwrap_from_request(uv_work_t* req) { - return (iotjs_gpio_reqwrap_t*)(iotjs_reqwrap_from_request((uv_req_t*)req)); -} + // Mode + jerry_value_t jmode = + iotjs_jval_get_property(jconfigurable, IOTJS_MAGIC_STRING_MODE); + if (jerry_value_is_undefined(jmode)) { + gpio->mode = kGpioModeNone; + } else { + if (jerry_value_is_number(jmode)) { + gpio->mode = (GpioMode)iotjs_jval_as_number(jmode); + } else { + gpio->mode = __kGpioModeMax; + } + if (gpio->mode >= __kGpioModeMax) { + return JS_CREATE_ERROR(TYPE, + "Bad arguments - gpio.mode should be MODE.NONE, " + "PULLUP, PULLDOWN, FLOAT, PUSHPULL or OPENDRAIN"); + + } else if (gpio->direction == kGpioDirectionIn && + gpio->mode != kGpioModeNone && gpio->mode != kGpioModePullup && + gpio->mode != kGpioModePulldown) { + return JS_CREATE_ERROR(TYPE, + "Bad arguments - DIRECTION.IN only supports " + "MODE.NONE, PULLUP and PULLDOWN"); + + } else if (gpio->direction == kGpioDirectionOut && + gpio->mode != kGpioModeNone && gpio->mode != kGpioModeFloat && + gpio->mode != kGpioModePushpull && + gpio->mode != kGpioModeOpendrain) { + return JS_CREATE_ERROR(TYPE, + "Bad arguments - DIRECTION.OUT only supports " + "MODE.NONE, FLOAT, PUSHPULL and OPENDRAIN"); + } + } + jerry_release_value(jmode); -iotjs_gpio_reqdata_t* iotjs_gpio_reqwrap_data(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_gpio_reqwrap_t, gpio_reqwrap); - return &_this->req_data; -} + // Edge + jerry_value_t jedge = + iotjs_jval_get_property(jconfigurable, IOTJS_MAGIC_STRING_EDGE); + if (jerry_value_is_undefined(jedge)) { + gpio->edge = kGpioEdgeNone; + } else { + if (jerry_value_is_number(jedge)) { + gpio->edge = (GpioEdge)iotjs_jval_as_number(jedge); + } else { + gpio->edge = __kGpioEdgeMax; + } + if (gpio->edge >= __kGpioEdgeMax) { + jerry_release_value(jedge); + return JS_CREATE_ERROR(TYPE, + "Bad arguments - gpio.edge should be EDGE.NONE, " + "RISING, FALLING or BOTH"); + } + } + jerry_release_value(jedge); -iotjs_gpio_t* iotjs_gpio_instance_from_reqwrap(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_gpio_reqwrap_t, gpio_reqwrap); - return _this->gpio_instance; + return jerry_create_undefined(); } +JS_FUNCTION(gpio_constructor) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(1, object); + DJS_CHECK_ARG_IF_EXIST(1, function); -#undef THIS + // Create GPIO object + const jerry_value_t jgpio = JS_GET_THIS(); + iotjs_gpio_t* gpio = gpio_create(jgpio); + jerry_value_t config_res = + gpio_set_configuration(gpio, JS_GET_ARG(0, object)); + if (jerry_value_is_error(config_res)) { + return config_res; + } + IOTJS_ASSERT(jerry_value_is_undefined(config_res)); -static void iotjs_gpio_write_worker(uv_work_t* work_req) { - GPIO_WORKER_INIT; + const jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(1, function); - if (!iotjs_gpio_write(gpio, req_data->value)) { - req_data->result = false; - return; + // If the callback doesn't exist, it is completed synchronously. + // Otherwise, it will be executed asynchronously. + if (!jerry_value_is_null(jcallback)) { + iotjs_periph_call_async(gpio, jcallback, kGpioOpOpen, gpio_worker); + } else if (!iotjs_gpio_open(gpio)) { + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kGpioOpOpen)); } - req_data->result = true; + return jerry_create_undefined(); } +JS_FUNCTION(gpio_close) { + JS_DECLARE_THIS_PTR(gpio, gpio); + DJS_CHECK_ARG_IF_EXIST(0, function); -static void iotjs_gpio_read_worker(uv_work_t* work_req) { - GPIO_WORKER_INIT; + iotjs_periph_call_async(gpio, JS_GET_ARG_IF_EXIST(0, function), kGpioOpClose, + gpio_worker); - int result = iotjs_gpio_read(gpio); - if (result < 0) { - req_data->result = false; - return; - } - req_data->result = true; - req_data->value = (bool)result; + return jerry_create_undefined(); } - -static void iotjs_gpio_close_worker(uv_work_t* work_req) { - GPIO_WORKER_INIT; +JS_FUNCTION(gpio_close_sync) { + JS_DECLARE_THIS_PTR(gpio, gpio); if (!iotjs_gpio_close(gpio)) { - req_data->result = false; - return; + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kGpioOpClose)); } - req_data->result = true; + return jerry_create_undefined(); } +typedef enum { IOTJS_GPIO_WRITE, IOTJS_GPIO_WRITESYNC } iotjs_gpio_op_t; -static void iotjs_gpio_after_worker(uv_work_t* work_req, int status) { - iotjs_gpio_reqwrap_t* req_wrap = iotjs_gpio_reqwrap_from_request(work_req); - iotjs_gpio_reqdata_t* req_data = iotjs_gpio_reqwrap_data(req_wrap); - iotjs_jargs_t jargs = iotjs_jargs_create(2); - bool result = req_data->result; +jerry_value_t gpio_do_write_or_writesync(const jerry_value_t jfunc, + const jerry_value_t jthis, + const jerry_value_t jargv[], + const jerry_length_t jargc, + const iotjs_gpio_op_t gpio_op) { + JS_DECLARE_THIS_PTR(gpio, gpio); - if (status) { - iotjs_jargs_append_error(&jargs, "GPIO System Error"); + bool value; + if (jerry_value_is_number(jargv[0])) { + value = (bool)jerry_get_number_value(jargv[0]); + } else if (jerry_value_is_boolean(jargv[0])) { + value = jerry_get_boolean_value(jargv[0]); } else { - switch (req_data->op) { - case kGpioOpOpen: - if (!result) { - iotjs_jargs_append_error(&jargs, "GPIO Open Error"); - } else { - iotjs_jargs_append_null(&jargs); - } - break; - case kGpioOpWrite: - if (!result) { - iotjs_jargs_append_error(&jargs, "GPIO Write Error"); - } else { - iotjs_jargs_append_null(&jargs); - } - break; - case kGpioOpRead: - if (!result) { - iotjs_jargs_append_error(&jargs, "GPIO Read Error"); - } else { - iotjs_jargs_append_null(&jargs); - iotjs_jargs_append_bool(&jargs, req_data->value); - } - break; - case kGpioOpClose: - if (!result) { - iotjs_jargs_append_error(&jargs, "GPIO Close Error"); - } else { - iotjs_jargs_append_null(&jargs); - } - break; - default: - IOTJS_ASSERT(!"Unreachable"); - break; + const jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(1, function); + if (gpio_op == IOTJS_GPIO_WRITE && !jerry_value_is_null(jcallback)) { + const char* error_msg = iotjs_periph_error_str(kGpioOpWrite); + jerry_value_t error_str = jerry_create_string((jerry_char_t*)error_msg); + iotjs_invoke_callback(jcallback, jthis, &error_str, 1); + jerry_release_value(error_str); + return jerry_create_undefined(); } - } - const iotjs_jval_t* jcallback = iotjs_gpio_reqwrap_jcallback(req_wrap); - iotjs_make_callback(jcallback, iotjs_jval_get_undefined(), &jargs); + return JS_CREATE_ERROR(TYPE, "GPIO WriteSync Error - Wrong argument type"); + } - iotjs_jargs_destroy(&jargs); + gpio->value = value; + if (gpio_op == IOTJS_GPIO_WRITE) { + DJS_CHECK_ARG_IF_EXIST(1, function); + iotjs_periph_call_async(gpio, JS_GET_ARG_IF_EXIST(1, function), + kGpioOpWrite, gpio_worker); + } else { + if (!iotjs_gpio_write(gpio)) { + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kGpioOpWrite)); + } + } - iotjs_gpio_reqwrap_dispatched(req_wrap); + return jerry_create_undefined(); } - -static void gpio_set_configurable(iotjs_gpio_t* gpio, - const iotjs_jval_t* jconfigurable) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_gpio_t, gpio); - - iotjs_jval_t jpin = - iotjs_jval_get_property(jconfigurable, IOTJS_MAGIC_STRING_PIN); - _this->pin = iotjs_jval_as_number(&jpin); - iotjs_jval_destroy(&jpin); - - iotjs_jval_t jdirection = - iotjs_jval_get_property(jconfigurable, IOTJS_MAGIC_STRING_DIRECTION); - _this->direction = (GpioDirection)iotjs_jval_as_number(&jdirection); - iotjs_jval_destroy(&jdirection); - - iotjs_jval_t jmode = - iotjs_jval_get_property(jconfigurable, IOTJS_MAGIC_STRING_MODE); - _this->mode = (GpioMode)iotjs_jval_as_number(&jmode); - iotjs_jval_destroy(&jmode); - - iotjs_jval_t jedge = - iotjs_jval_get_property(jconfigurable, IOTJS_MAGIC_STRING_EDGE); - _this->edge = (GpioMode)iotjs_jval_as_number(&jedge); - iotjs_jval_destroy(&jedge); +JS_FUNCTION(gpio_write) { + return gpio_do_write_or_writesync(jfunc, jthis, jargv, jargc, + IOTJS_GPIO_WRITE); } - -#define GPIO_ASYNC(call, this, jcallback, op) \ - do { \ - uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get()); \ - iotjs_gpio_reqwrap_t* req_wrap = \ - iotjs_gpio_reqwrap_create(jcallback, this, op); \ - uv_work_t* req = iotjs_gpio_reqwrap_req(req_wrap); \ - uv_queue_work(loop, req, iotjs_gpio_##call##_worker, \ - iotjs_gpio_after_worker); \ - } while (0) - - -#define GPIO_ASYNC_WITH_VALUE(call, this, jcallback, op, val) \ - do { \ - uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get()); \ - iotjs_gpio_reqwrap_t* req_wrap = \ - iotjs_gpio_reqwrap_create(jcallback, this, op); \ - uv_work_t* req = iotjs_gpio_reqwrap_req(req_wrap); \ - iotjs_gpio_reqdata_t* req_data = iotjs_gpio_reqwrap_data(req_wrap); \ - req_data->value = val; \ - uv_queue_work(loop, req, iotjs_gpio_##call##_worker, \ - iotjs_gpio_after_worker); \ - } while (0) - - -JHANDLER_FUNCTION(GpioConstructor) { - DJHANDLER_CHECK_THIS(object); - DJHANDLER_CHECK_ARGS(2, object, function); - - // Create GPIO object - const iotjs_jval_t* jgpio = JHANDLER_GET_THIS(object); - iotjs_gpio_t* gpio = iotjs_gpio_create(jgpio); - IOTJS_ASSERT(gpio == iotjs_gpio_instance_from_jval(jgpio)); - - gpio_set_configurable(gpio, JHANDLER_GET_ARG(0, object)); - - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG(1, function); - GPIO_ASYNC(open, gpio, jcallback, kGpioOpOpen); +JS_FUNCTION(gpio_write_sync) { + return gpio_do_write_or_writesync(jfunc, jthis, jargv, jargc, + IOTJS_GPIO_WRITESYNC); } +JS_FUNCTION(gpio_read) { + JS_DECLARE_THIS_PTR(gpio, gpio); + DJS_CHECK_ARG_IF_EXIST(0, function); -JHANDLER_FUNCTION(Write) { - JHANDLER_DECLARE_THIS_PTR(gpio, gpio); - DJHANDLER_CHECK_ARGS(1, boolean); - DJHANDLER_CHECK_ARG_IF_EXIST(1, function); + iotjs_periph_call_async(gpio, JS_GET_ARG_IF_EXIST(0, function), kGpioOpRead, + gpio_worker); - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(1, function); + return jerry_create_undefined(); +} - bool value = JHANDLER_GET_ARG(0, boolean); +JS_FUNCTION(gpio_read_sync) { + JS_DECLARE_THIS_PTR(gpio, gpio); - if (jcallback) { - GPIO_ASYNC_WITH_VALUE(write, gpio, jcallback, kGpioOpWrite, value); - } else { - if (!iotjs_gpio_write(gpio, value)) { - JHANDLER_THROW(COMMON, "GPIO WriteSync Error"); - } + if (!iotjs_gpio_read(gpio)) { + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kGpioOpRead)); } - iotjs_jhandler_return_null(jhandler); + return jerry_create_boolean(gpio->value); } +JS_FUNCTION(gpio_set_direction_sync) { + DJS_CHECK_ARGS(1, number); + JS_DECLARE_THIS_PTR(gpio, gpio); -JHANDLER_FUNCTION(Read) { - JHANDLER_DECLARE_THIS_PTR(gpio, gpio); - DJHANDLER_CHECK_ARGS(0); - DJHANDLER_CHECK_ARG_IF_EXIST(0, function); - - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(0, function); - - if (jcallback) { - GPIO_ASYNC(read, gpio, jcallback, kGpioOpRead); - iotjs_jhandler_return_null(jhandler); - } else { - int value = iotjs_gpio_read(gpio); - if (value < 0) { - JHANDLER_THROW(COMMON, "GPIO ReadSync Error"); - } - iotjs_jhandler_return_boolean(jhandler, value); + int direction; + JS_GET_REQUIRED_ARG_VALUE(0, direction, IOTJS_MAGIC_STRING_DIRECTION, number); + if (direction >= __kGpioDirectionMax) { + return JS_CREATE_ERROR( + TYPE, "Bad arguments - gpio.direction should be DIRECTION.IN or OUT"); } -} - + gpio->direction = direction; -JHANDLER_FUNCTION(Close) { - JHANDLER_DECLARE_THIS_PTR(gpio, gpio) - DJHANDLER_CHECK_ARG_IF_EXIST(0, function); - - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(0, function); - - if (jcallback) { - GPIO_ASYNC(close, gpio, jcallback, kGpioOpClose); - } else { - if (!iotjs_gpio_close(gpio)) { - JHANDLER_THROW(COMMON, "GPIO CloseSync Error"); - } + if (!iotjs_gpio_set_direction(gpio)) { + return JS_CREATE_ERROR( + COMMON, "GPIO SetDirectionSync Error - Cannot set direction"); } - iotjs_jhandler_return_null(jhandler); + return jerry_create_undefined(); } +jerry_value_t iotjs_init_gpio(void) { + jerry_value_t jgpio_const = jerry_create_external_function(gpio_constructor); + + jerry_value_t jprototype = jerry_create_object(); -iotjs_jval_t InitGpio() { - iotjs_jval_t jgpio = iotjs_jval_create_object(); - iotjs_jval_t jgpioConstructor = - iotjs_jval_create_function_with_dispatch(GpioConstructor); - iotjs_jval_set_property_jval(&jgpio, IOTJS_MAGIC_STRING_GPIO, - &jgpioConstructor); + iotjs_jval_set_method(jprototype, IOTJS_MAGIC_STRING_CLOSE, gpio_close); + iotjs_jval_set_method(jprototype, IOTJS_MAGIC_STRING_CLOSESYNC, + gpio_close_sync); + iotjs_jval_set_method(jprototype, IOTJS_MAGIC_STRING_WRITE, gpio_write); + iotjs_jval_set_method(jprototype, IOTJS_MAGIC_STRING_WRITESYNC, + gpio_write_sync); + iotjs_jval_set_method(jprototype, IOTJS_MAGIC_STRING_READ, gpio_read); + iotjs_jval_set_method(jprototype, IOTJS_MAGIC_STRING_READSYNC, + gpio_read_sync); + iotjs_jval_set_method(jprototype, IOTJS_MAGIC_STRING_SETDIRECTIONSYNC, + gpio_set_direction_sync); - iotjs_jval_t jprototype = iotjs_jval_create_object(); - iotjs_jval_set_method(&jprototype, IOTJS_MAGIC_STRING_WRITE, Write); - iotjs_jval_set_method(&jprototype, IOTJS_MAGIC_STRING_READ, Read); - iotjs_jval_set_method(&jprototype, IOTJS_MAGIC_STRING_CLOSE, Close); - iotjs_jval_set_property_jval(&jgpioConstructor, IOTJS_MAGIC_STRING_PROTOTYPE, - &jprototype); - iotjs_jval_destroy(&jprototype); - iotjs_jval_destroy(&jgpioConstructor); + iotjs_jval_set_property_jval(jgpio_const, IOTJS_MAGIC_STRING_PROTOTYPE, + jprototype); + jerry_release_value(jprototype); // GPIO direction properties - iotjs_jval_t jdirection = iotjs_jval_create_object(); - iotjs_jval_set_property_number(&jdirection, IOTJS_MAGIC_STRING_IN, + jerry_value_t jdirection = jerry_create_object(); + iotjs_jval_set_property_number(jdirection, IOTJS_MAGIC_STRING_IN, kGpioDirectionIn); - iotjs_jval_set_property_number(&jdirection, IOTJS_MAGIC_STRING_OUT, + iotjs_jval_set_property_number(jdirection, IOTJS_MAGIC_STRING_OUT_U, kGpioDirectionOut); - iotjs_jval_set_property_jval(&jgpio, IOTJS_MAGIC_STRING_DIRECTION_U, - &jdirection); - iotjs_jval_destroy(&jdirection); + iotjs_jval_set_property_jval(jgpio_const, IOTJS_MAGIC_STRING_DIRECTION_U, + jdirection); + jerry_release_value(jdirection); // GPIO mode properties - iotjs_jval_t jmode = iotjs_jval_create_object(); - iotjs_jval_set_property_number(&jmode, IOTJS_MAGIC_STRING_NONE, + jerry_value_t jmode = jerry_create_object(); + iotjs_jval_set_property_number(jmode, IOTJS_MAGIC_STRING_NONE_U, kGpioModeNone); #if defined(__NUTTX__) - iotjs_jval_set_property_number(&jmode, IOTJS_MAGIC_STRING_PULLUP, + iotjs_jval_set_property_number(jmode, IOTJS_MAGIC_STRING_PULLUP_U, kGpioModePullup); - iotjs_jval_set_property_number(&jmode, IOTJS_MAGIC_STRING_PULLDOWN, + iotjs_jval_set_property_number(jmode, IOTJS_MAGIC_STRING_PULLDOWN_U, kGpioModePulldown); - iotjs_jval_set_property_number(&jmode, IOTJS_MAGIC_STRING_FLOAT, + iotjs_jval_set_property_number(jmode, IOTJS_MAGIC_STRING_FLOAT_U, kGpioModeFloat); - iotjs_jval_set_property_number(&jmode, IOTJS_MAGIC_STRING_PUSHPULL, + iotjs_jval_set_property_number(jmode, IOTJS_MAGIC_STRING_PUSHPULL_U, kGpioModePushpull); - iotjs_jval_set_property_number(&jmode, IOTJS_MAGIC_STRING_OPENDRAIN, + iotjs_jval_set_property_number(jmode, IOTJS_MAGIC_STRING_OPENDRAIN_U, kGpioModeOpendrain); #endif - iotjs_jval_set_property_jval(&jgpio, IOTJS_MAGIC_STRING_MODE_U, &jmode); - iotjs_jval_destroy(&jmode); + iotjs_jval_set_property_jval(jgpio_const, IOTJS_MAGIC_STRING_MODE_U, jmode); + jerry_release_value(jmode); // GPIO edge properties - iotjs_jval_t jedge = iotjs_jval_create_object(); - iotjs_jval_set_property_number(&jedge, IOTJS_MAGIC_STRING_NONE, + jerry_value_t jedge = jerry_create_object(); + iotjs_jval_set_property_number(jedge, IOTJS_MAGIC_STRING_NONE_U, kGpioEdgeNone); - iotjs_jval_set_property_number(&jedge, IOTJS_MAGIC_STRING_RISING_U, + iotjs_jval_set_property_number(jedge, IOTJS_MAGIC_STRING_RISING_U, kGpioEdgeRising); - iotjs_jval_set_property_number(&jedge, IOTJS_MAGIC_STRING_FALLING_U, + iotjs_jval_set_property_number(jedge, IOTJS_MAGIC_STRING_FALLING_U, kGpioEdgeFalling); - iotjs_jval_set_property_number(&jedge, IOTJS_MAGIC_STRING_BOTH_U, + iotjs_jval_set_property_number(jedge, IOTJS_MAGIC_STRING_BOTH_U, kGpioEdgeBoth); - iotjs_jval_set_property_jval(&jgpio, IOTJS_MAGIC_STRING_EDGE_U, &jedge); - iotjs_jval_destroy(&jedge); + iotjs_jval_set_property_jval(jgpio_const, IOTJS_MAGIC_STRING_EDGE_U, jedge); + jerry_release_value(jedge); - return jgpio; + return jgpio_const; } diff --git a/src/modules/iotjs_module_gpio.h b/src/modules/iotjs_module_gpio.h index 3ba87d37c2..d0557c7efb 100644 --- a/src/modules/iotjs_module_gpio.h +++ b/src/modules/iotjs_module_gpio.h @@ -19,19 +19,15 @@ #include "iotjs_def.h" -#include "iotjs_objectwrap.h" -#include "iotjs_reqwrap.h" +#include "iotjs_module_periph_common.h" -#if defined(__TIZENRT__) -#include -#endif typedef enum { kGpioDirectionIn = 0, kGpioDirectionOut, + __kGpioDirectionMax } GpioDirection; - typedef enum { kGpioModeNone = 0, kGpioModePullup, @@ -39,76 +35,41 @@ typedef enum { kGpioModeFloat, kGpioModePushpull, kGpioModeOpendrain, + __kGpioModeMax } GpioMode; - typedef enum { kGpioEdgeNone = 0, kGpioEdgeRising, kGpioEdgeFalling, kGpioEdgeBoth, + __kGpioEdgeMax } GpioEdge; - -typedef enum { - kGpioOpOpen, - kGpioOpWrite, - kGpioOpRead, - kGpioOpClose, -} GpioOp; - - -typedef struct { - bool value; - bool result; - GpioOp op; -} iotjs_gpio_reqdata_t; - +typedef struct iotjs_gpio_platform_data_s iotjs_gpio_platform_data_t; // This Gpio class provides interfaces for GPIO operation. typedef struct { - iotjs_jobjectwrap_t jobjectwrap; + jerry_value_t jobject; + iotjs_gpio_platform_data_t* platform_data; + + bool value; uint32_t pin; GpioDirection direction; GpioMode mode; GpioEdge edge; -#if defined(__linux__) - int value_fd; - uv_thread_t thread; - uv_mutex_t mutex; -#elif defined(__TIZENRT__) - iotbus_gpio_context_h gpio_context; -#endif -} IOTJS_VALIDATED_STRUCT(iotjs_gpio_t); - +} iotjs_gpio_t; -typedef struct { - iotjs_reqwrap_t reqwrap; - uv_work_t req; - iotjs_gpio_reqdata_t req_data; - iotjs_gpio_t* gpio_instance; -} IOTJS_VALIDATED_STRUCT(iotjs_gpio_reqwrap_t); - - -#define THIS iotjs_gpio_reqwrap_t* gpio_reqwrap - -iotjs_gpio_reqwrap_t* iotjs_gpio_reqwrap_from_request(uv_work_t* req); -iotjs_gpio_reqdata_t* iotjs_gpio_reqwrap_data(THIS); - -iotjs_gpio_t* iotjs_gpio_instance_from_reqwrap(THIS); - -#undef THIS - - -#define GPIO_WORKER_INIT \ - iotjs_gpio_reqwrap_t* req_wrap = iotjs_gpio_reqwrap_from_request(work_req); \ - iotjs_gpio_reqdata_t* req_data = iotjs_gpio_reqwrap_data(req_wrap); \ - iotjs_gpio_t* gpio = iotjs_gpio_instance_from_reqwrap(req_wrap); - - -void iotjs_gpio_open_worker(uv_work_t* work_req); -bool iotjs_gpio_write(iotjs_gpio_t* gpio, bool value); -int iotjs_gpio_read(iotjs_gpio_t* gpio); +bool iotjs_gpio_open(iotjs_gpio_t* gpio); +bool iotjs_gpio_write(iotjs_gpio_t* gpio); +bool iotjs_gpio_read(iotjs_gpio_t* gpio); bool iotjs_gpio_close(iotjs_gpio_t* gpio); +bool iotjs_gpio_set_direction(iotjs_gpio_t* gpio); + +// Platform-related functions; they are implemented +// by platform code (i.e.: linux, nuttx, tizen). +void iotjs_gpio_create_platform_data(iotjs_gpio_t* gpio); +void iotjs_gpio_destroy_platform_data( + iotjs_gpio_platform_data_t* platform_data); #endif /* IOTJS_MODULE_GPIO_H */ diff --git a/src/modules/iotjs_module_http_parser.c b/src/modules/iotjs_module_http_parser.c new file mode 100644 index 0000000000..1c614c2f83 --- /dev/null +++ b/src/modules/iotjs_module_http_parser.c @@ -0,0 +1,500 @@ +/* Copyright 2015-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_def.h" +#include "iotjs_module_buffer.h" +#include +#include +#include + +#include "http_parser.h" + + +// If # of header fields == HEADER_MAX, flush header to JS side. +// This is weired : # of maximum headers in C equals to HEADER_MAX-1. +// This is because , OnHeaders cb, we increase n_fields first, +// and check whether field == HEADER_MAX. +// ex) HEADER_MAX 2 means that we can keep at most 1 header field/value +// during http parsing. +// Increase this to minimize inter JS-C call +#define HEADER_MAX 10 + + +typedef struct { + jerry_value_t jobject; + + http_parser parser; + + iotjs_string_t url; + iotjs_string_t status_msg; + + iotjs_string_t fields[HEADER_MAX]; + iotjs_string_t values[HEADER_MAX]; + size_t n_fields; + size_t n_values; + + jerry_value_t cur_jbuf; + char* cur_buf; + size_t cur_buf_len; + + bool flushed; +} iotjs_http_parserwrap_t; + + +typedef enum http_parser_type http_parser_type; + + +static void iotjs_http_parserwrap_initialize( + iotjs_http_parserwrap_t* http_parserwrap, http_parser_type type) { + http_parser_init(&http_parserwrap->parser, type); + iotjs_string_destroy(&http_parserwrap->url); + iotjs_string_destroy(&http_parserwrap->status_msg); + http_parserwrap->n_fields = 0; + http_parserwrap->n_values = 0; + http_parserwrap->flushed = false; + http_parserwrap->cur_jbuf = jerry_create_null(); + http_parserwrap->cur_buf = NULL; + http_parserwrap->cur_buf_len = 0; +} + + +IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(http_parserwrap); + + +static void iotjs_http_parserwrap_create(const jerry_value_t jparser, + http_parser_type type) { + iotjs_http_parserwrap_t* http_parserwrap = + IOTJS_ALLOC(iotjs_http_parserwrap_t); + http_parserwrap->jobject = jparser; + jerry_set_object_native_pointer(jparser, http_parserwrap, + &this_module_native_info); + + http_parserwrap->url = iotjs_string_create(); + http_parserwrap->status_msg = iotjs_string_create(); + for (size_t i = 0; i < HEADER_MAX; i++) { + http_parserwrap->fields[i] = iotjs_string_create(); + http_parserwrap->values[i] = iotjs_string_create(); + } + + iotjs_http_parserwrap_initialize(http_parserwrap, type); + http_parserwrap->parser.data = http_parserwrap; + + IOTJS_ASSERT(jerry_value_is_object(http_parserwrap->jobject)); +} + + +static void iotjs_http_parserwrap_destroy( + iotjs_http_parserwrap_t* http_parserwrap) { + iotjs_string_destroy(&http_parserwrap->url); + iotjs_string_destroy(&http_parserwrap->status_msg); + for (size_t i = 0; i < HEADER_MAX; i++) { + iotjs_string_destroy(&http_parserwrap->fields[i]); + iotjs_string_destroy(&http_parserwrap->values[i]); + } + + IOTJS_RELEASE(http_parserwrap); +} + + +static jerry_value_t iotjs_http_parserwrap_make_header( + iotjs_http_parserwrap_t* http_parserwrap) { + jerry_value_t jheader = jerry_create_array(http_parserwrap->n_values * 2); + for (size_t i = 0; i < http_parserwrap->n_values; i++) { + jerry_value_t f = iotjs_jval_create_string(&http_parserwrap->fields[i]); + jerry_value_t v = iotjs_jval_create_string(&http_parserwrap->values[i]); + iotjs_jval_set_property_by_index(jheader, i * 2, f); + iotjs_jval_set_property_by_index(jheader, i * 2 + 1, v); + jerry_release_value(f); + jerry_release_value(v); + } + return jheader; +} + + +static void iotjs_http_parserwrap_flush( + iotjs_http_parserwrap_t* http_parserwrap) { + const jerry_value_t jobj = http_parserwrap->jobject; + jerry_value_t func = + iotjs_jval_get_property(jobj, IOTJS_MAGIC_STRING_ONHEADERS); + IOTJS_ASSERT(jerry_value_is_function(func)); + + jerry_value_t jheader = iotjs_http_parserwrap_make_header(http_parserwrap); + size_t argc = 1; + jerry_value_t argv[2] = { jheader, 0 }; + + if (http_parserwrap->parser.type == HTTP_REQUEST && + !iotjs_string_is_empty(&http_parserwrap->url)) { + argv[argc++] = iotjs_jval_create_string(&http_parserwrap->url); + } + + iotjs_invoke_callback(func, jobj, argv, argc); + + iotjs_string_destroy(&http_parserwrap->url); + for (size_t i = 0; i < argc; i++) { + jerry_release_value(argv[i]); + } + jerry_release_value(func); + http_parserwrap->flushed = true; +} + + +static void iotjs_http_parserwrap_set_buf( + iotjs_http_parserwrap_t* http_parserwrap, jerry_value_t jbuf, char* buf, + size_t sz) { + http_parserwrap->cur_jbuf = jbuf; + http_parserwrap->cur_buf = buf; + http_parserwrap->cur_buf_len = sz; +} + + +// http-parser callbacks +static int iotjs_http_parserwrap_on_message_begin(http_parser* parser) { + iotjs_http_parserwrap_t* http_parserwrap = + (iotjs_http_parserwrap_t*)(parser->data); + iotjs_string_destroy(&http_parserwrap->url); + iotjs_string_destroy(&http_parserwrap->status_msg); + return 0; +} + + +static int iotjs_http_parserwrap_on_url(http_parser* parser, const char* at, + size_t length) { + iotjs_http_parserwrap_t* http_parserwrap = + (iotjs_http_parserwrap_t*)(parser->data); + iotjs_string_append(&http_parserwrap->url, at, length); + return 0; +} + + +static int iotjs_http_parserwrap_on_status(http_parser* parser, const char* at, + size_t length) { + iotjs_http_parserwrap_t* http_parserwrap = + (iotjs_http_parserwrap_t*)(parser->data); + iotjs_string_append(&http_parserwrap->status_msg, at, length); + return 0; +} + + +static int iotjs_http_parserwrap_on_header_field(http_parser* parser, + const char* at, + size_t length) { + iotjs_http_parserwrap_t* http_parserwrap = + (iotjs_http_parserwrap_t*)(parser->data); + if (http_parserwrap->n_fields == http_parserwrap->n_values) { + http_parserwrap->n_fields++; + // values and fields are flushed to JS + // before corresponding OnHeaderValue is called. + if (http_parserwrap->n_fields == HEADER_MAX) { + iotjs_http_parserwrap_flush(http_parserwrap); // to JS world + http_parserwrap->n_fields = 1; + http_parserwrap->n_values = 0; + } + iotjs_string_destroy( + &http_parserwrap->fields[http_parserwrap->n_fields - 1]); + } + IOTJS_ASSERT(http_parserwrap->n_fields == http_parserwrap->n_values + 1); + iotjs_string_append(&http_parserwrap->fields[http_parserwrap->n_fields - 1], + at, length); + + return 0; +} + + +static int iotjs_http_parserwrap_on_header_value(http_parser* parser, + const char* at, + size_t length) { + iotjs_http_parserwrap_t* http_parserwrap = + (iotjs_http_parserwrap_t*)(parser->data); + if (http_parserwrap->n_fields != http_parserwrap->n_values) { + http_parserwrap->n_values++; + iotjs_string_destroy( + &http_parserwrap->values[http_parserwrap->n_values - 1]); + } + + IOTJS_ASSERT(http_parserwrap->n_fields == http_parserwrap->n_values); + + iotjs_string_append(&http_parserwrap->values[http_parserwrap->n_values - 1], + at, length); + + return 0; +} + + +static int iotjs_http_parserwrap_on_headers_complete(http_parser* parser) { + iotjs_http_parserwrap_t* http_parserwrap = + (iotjs_http_parserwrap_t*)(parser->data); + const jerry_value_t jobj = http_parserwrap->jobject; + jerry_value_t func = + iotjs_jval_get_property(jobj, IOTJS_MAGIC_STRING_ONHEADERSCOMPLETE); + IOTJS_ASSERT(jerry_value_is_function(func)); + + // URL + jerry_value_t info = jerry_create_object(); + + if (http_parserwrap->flushed) { + // If some headers already are flushed, + // flush the remaining headers. + // In Flush function, url is already flushed to JS. + iotjs_http_parserwrap_flush(http_parserwrap); + } else { + // Here, there was no flushed header. + // We need to make a new header object with all header fields + jerry_value_t jheader = iotjs_http_parserwrap_make_header(http_parserwrap); + iotjs_jval_set_property_jval(info, IOTJS_MAGIC_STRING_HEADERS, jheader); + jerry_release_value(jheader); + if (http_parserwrap->parser.type == HTTP_REQUEST) { + IOTJS_ASSERT(!iotjs_string_is_empty(&http_parserwrap->url)); + iotjs_jval_set_property_string(info, IOTJS_MAGIC_STRING_URL, + &http_parserwrap->url); + } + } + http_parserwrap->n_fields = http_parserwrap->n_values = 0; + + // Method + if (http_parserwrap->parser.type == HTTP_REQUEST) { + iotjs_jval_set_property_number(info, IOTJS_MAGIC_STRING_METHOD, + http_parserwrap->parser.method); + } + // Status + else if (http_parserwrap->parser.type == HTTP_RESPONSE) { + iotjs_jval_set_property_number(info, IOTJS_MAGIC_STRING_STATUS, + http_parserwrap->parser.status_code); + iotjs_jval_set_property_string(info, IOTJS_MAGIC_STRING_STATUS_MSG, + &http_parserwrap->status_msg); + } + + + // For future support, current http_server module does not support + // upgrade and keepalive. + // upgrade + iotjs_jval_set_property_boolean(info, IOTJS_MAGIC_STRING_UPGRADE, + http_parserwrap->parser.upgrade); + // shouldkeepalive + iotjs_jval_set_property_boolean(info, IOTJS_MAGIC_STRING_SHOULDKEEPALIVE, + http_should_keep_alive( + &http_parserwrap->parser)); + + // http version number + iotjs_jval_set_property_number(info, IOTJS_MAGIC_STRING_HTTP_VERSION_MAJOR, + parser->http_major); + iotjs_jval_set_property_number(info, IOTJS_MAGIC_STRING_HTTP_VERSION_MINOR, + parser->http_minor); + + jerry_value_t res = iotjs_invoke_callback_with_result(func, jobj, &info, 1); + + int ret = 1; + if (jerry_value_is_boolean(res)) { + ret = iotjs_jval_as_boolean(res); + } else if (jerry_value_is_error(res)) { + ret = 0; + } + + jerry_release_value(func); + jerry_release_value(res); + jerry_release_value(info); + + return ret; +} + + +static int iotjs_http_parserwrap_on_body(http_parser* parser, const char* at, + size_t length) { + iotjs_http_parserwrap_t* http_parserwrap = + (iotjs_http_parserwrap_t*)(parser->data); + const jerry_value_t jobj = http_parserwrap->jobject; + jerry_value_t func = iotjs_jval_get_property(jobj, IOTJS_MAGIC_STRING_ONBODY); + IOTJS_ASSERT(jerry_value_is_function(func)); + + jerry_value_t argv[3] = { http_parserwrap->cur_jbuf, + jerry_create_number(at - http_parserwrap->cur_buf), + jerry_create_number(length) }; + + iotjs_invoke_callback(func, jobj, argv, 3); + + jerry_release_value(argv[1]); + jerry_release_value(argv[2]); + jerry_release_value(func); + + return 0; +} + + +static int iotjs_http_parserwrap_on_message_complete(http_parser* parser) { + iotjs_http_parserwrap_t* http_parserwrap = + (iotjs_http_parserwrap_t*)(parser->data); + const jerry_value_t jobj = http_parserwrap->jobject; + jerry_value_t func = + iotjs_jval_get_property(jobj, IOTJS_MAGIC_STRING_ONMESSAGECOMPLETE); + IOTJS_ASSERT(jerry_value_is_function(func)); + + iotjs_invoke_callback(func, jobj, NULL, 0); + + jerry_release_value(func); + + return 0; +} + + +const struct http_parser_settings settings = { + iotjs_http_parserwrap_on_message_begin, + iotjs_http_parserwrap_on_url, + iotjs_http_parserwrap_on_status, + iotjs_http_parserwrap_on_header_field, + iotjs_http_parserwrap_on_header_value, + iotjs_http_parserwrap_on_headers_complete, + iotjs_http_parserwrap_on_body, + iotjs_http_parserwrap_on_message_complete, + NULL, /* on_chunk_header */ + NULL, /* on_chunk_complete */ +}; + + +static jerry_value_t iotjs_http_parser_return_parserrror( + http_parser* nativeparser) { + enum http_errno err = HTTP_PARSER_ERRNO(nativeparser); + + jerry_value_t eobj = + iotjs_jval_create_error_without_error_flag("Parse Error"); + iotjs_jval_set_property_number(eobj, IOTJS_MAGIC_STRING_BYTEPARSED, 0); + iotjs_jval_set_property_string_raw(eobj, IOTJS_MAGIC_STRING_CODE, + http_errno_name(err)); + return eobj; +} + + +JS_FUNCTION(js_func_finish) { + JS_DECLARE_THIS_PTR(http_parserwrap, parser); + + http_parser* nativeparser = &parser->parser; + size_t rv = http_parser_execute(nativeparser, &settings, NULL, 0); + + if (rv != 0) { + return iotjs_http_parser_return_parserrror(nativeparser); + } + + return jerry_create_undefined(); +} + + +JS_FUNCTION(js_func_execute) { + JS_DECLARE_THIS_PTR(http_parserwrap, parser); + DJS_CHECK_ARGS(1, object); + + jerry_value_t jbuffer = JS_GET_ARG(0, object); + iotjs_bufferwrap_t* buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuffer); + char* buf_data = buffer_wrap->buffer; + size_t buf_len = iotjs_bufferwrap_length(buffer_wrap); + DJS_CHECK(buf_data != NULL && buf_len > 0); + + iotjs_http_parserwrap_set_buf(parser, jbuffer, buf_data, buf_len); + + http_parser* nativeparser = &parser->parser; + size_t nparsed = + http_parser_execute(nativeparser, &settings, buf_data, buf_len); + + iotjs_http_parserwrap_set_buf(parser, jerry_create_null(), NULL, 0); + + + if (!nativeparser->upgrade && nparsed != buf_len) { + // nparsed should equal to buf_len except UPGRADE protocol + return iotjs_http_parser_return_parserrror(nativeparser); + } else { + return jerry_create_number(nparsed); + } +} + + +static jerry_value_t iotjs_http_parser_pause(jerry_value_t jthis, int paused) { + JS_DECLARE_THIS_PTR(http_parserwrap, parser); + + http_parser* nativeparser = &parser->parser; + http_parser_pause(nativeparser, paused); + return jerry_create_undefined(); +} + + +JS_FUNCTION(js_func_pause) { + return iotjs_http_parser_pause(jthis, 1); +} + + +JS_FUNCTION(js_func_resume) { + return iotjs_http_parser_pause(jthis, 0); +} + + +JS_FUNCTION(http_parser_cons) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(1, number); + + const jerry_value_t jparser = JS_GET_THIS(); + + http_parser_type httpparser_type = (http_parser_type)(JS_GET_ARG(0, number)); + + if (httpparser_type != HTTP_REQUEST && httpparser_type != HTTP_RESPONSE) { + return JS_CREATE_ERROR(TYPE, "Invalid type of HTTP."); + } + + iotjs_http_parserwrap_create(jparser, httpparser_type); + return jerry_create_undefined(); +} + +static void http_parser_register_methods_object(jerry_value_t target) { + jerry_value_t methods = jerry_create_array(26); + + jerry_value_t method_name; + uint32_t idx = 0; +#define V(num, name, string) \ + method_name = jerry_create_string((const jerry_char_t*)#string); \ + jerry_set_property_by_index(methods, idx++, method_name); \ + jerry_release_value(method_name); + + HTTP_METHOD_MAP(V); +#undef V + + iotjs_jval_set_property_jval(target, IOTJS_MAGIC_STRING_METHODS, methods); + jerry_release_value(methods); +} + +jerry_value_t iotjs_init_http_parser(void) { + jerry_value_t http_parser = jerry_create_object(); + + jerry_value_t jparser_cons = jerry_create_external_function(http_parser_cons); + iotjs_jval_set_property_jval(http_parser, IOTJS_MAGIC_STRING_HTTPPARSER, + jparser_cons); + + iotjs_jval_set_property_number(jparser_cons, IOTJS_MAGIC_STRING_REQUEST_U, + HTTP_REQUEST); + iotjs_jval_set_property_number(jparser_cons, IOTJS_MAGIC_STRING_RESPONSE_U, + HTTP_RESPONSE); + + http_parser_register_methods_object(jparser_cons); + + jerry_value_t prototype = jerry_create_object(); + + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_EXECUTE, js_func_execute); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_FINISH, js_func_finish); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_PAUSE, js_func_pause); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_RESUME, js_func_resume); + + iotjs_jval_set_property_jval(jparser_cons, IOTJS_MAGIC_STRING_PROTOTYPE, + prototype); + + jerry_release_value(jparser_cons); + jerry_release_value(prototype); + + return http_parser; +} diff --git a/src/modules/iotjs_module_httpparser.c b/src/modules/iotjs_module_httpparser.c deleted file mode 100644 index 98e80073ba..0000000000 --- a/src/modules/iotjs_module_httpparser.c +++ /dev/null @@ -1,494 +0,0 @@ -/* Copyright 2015-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_def.h" -#include "iotjs_module_httpparser.h" -#include "iotjs_module_buffer.h" -#include -#include -#include - - -#define THIS iotjs_httpparserwrap_t* httpparserwrap - - -IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(httpparserwrap); - - -iotjs_httpparserwrap_t* iotjs_httpparserwrap_create(const iotjs_jval_t* jparser, - http_parser_type type) { - iotjs_httpparserwrap_t* httpparserwrap = IOTJS_ALLOC(iotjs_httpparserwrap_t); - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_httpparserwrap_t, httpparserwrap); - - iotjs_jobjectwrap_initialize(&_this->jobjectwrap, jparser, - &this_module_native_info); - - _this->url = iotjs_string_create(); - _this->status_msg = iotjs_string_create(); - for (size_t i = 0; i < HEADER_MAX; i++) { - _this->fields[i] = iotjs_string_create(); - _this->values[i] = iotjs_string_create(); - } - - iotjs_httpparserwrap_initialize(httpparserwrap, type); - _this->parser.data = httpparserwrap; - - return httpparserwrap; -} - - -static void iotjs_httpparserwrap_destroy(THIS) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_httpparserwrap_t, httpparserwrap); - - iotjs_string_destroy(&_this->url); - iotjs_string_destroy(&_this->status_msg); - for (size_t i = 0; i < HEADER_MAX; i++) { - iotjs_string_destroy(&_this->fields[i]); - iotjs_string_destroy(&_this->values[i]); - } - iotjs_jobjectwrap_destroy(&_this->jobjectwrap); - - IOTJS_RELEASE(httpparserwrap); -} - - -void iotjs_httpparserwrap_initialize(THIS, http_parser_type type) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_httpparserwrap_t, httpparserwrap); - - http_parser_init(&_this->parser, type); - iotjs_string_make_empty(&_this->url); - iotjs_string_make_empty(&_this->status_msg); - _this->n_fields = 0; - _this->n_values = 0; - _this->flushed = false; - _this->cur_jbuf = NULL; - _this->cur_buf = NULL; - _this->cur_buf_len = 0; -} - - -// http-parser callbacks -static int iotjs_httpparserwrap_on_message_begin(http_parser* parser) { - iotjs_httpparserwrap_t* httpparserwrap = - (iotjs_httpparserwrap_t*)(parser->data); - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_httpparserwrap_t, httpparserwrap); - iotjs_string_make_empty(&_this->url); - iotjs_string_make_empty(&_this->status_msg); - return 0; -} - - -static int iotjs_httpparserwrap_on_url(http_parser* parser, const char* at, - size_t length) { - iotjs_httpparserwrap_t* httpparserwrap = - (iotjs_httpparserwrap_t*)(parser->data); - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_httpparserwrap_t, httpparserwrap); - iotjs_string_append(&_this->url, at, length); - return 0; -} - - -static int iotjs_httpparserwrap_on_status(http_parser* parser, const char* at, - size_t length) { - iotjs_httpparserwrap_t* httpparserwrap = - (iotjs_httpparserwrap_t*)(parser->data); - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_httpparserwrap_t, httpparserwrap); - iotjs_string_append(&_this->status_msg, at, length); - return 0; -} - - -static int iotjs_httpparserwrap_on_header_field(http_parser* parser, - const char* at, size_t length) { - iotjs_httpparserwrap_t* httpparserwrap = - (iotjs_httpparserwrap_t*)(parser->data); - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_httpparserwrap_t, httpparserwrap); - if (_this->n_fields == _this->n_values) { - _this->n_fields++; - // values and fields are flushed to JS - // before corresponding OnHeaderValue is called. - if (_this->n_fields == HEADER_MAX) { - iotjs_httpparserwrap_flush(httpparserwrap); // to JS world - _this->n_fields = 1; - _this->n_values = 0; - } - iotjs_string_make_empty(&_this->fields[_this->n_fields - 1]); - } - IOTJS_ASSERT(_this->n_fields == _this->n_values + 1); - iotjs_string_append(&_this->fields[_this->n_fields - 1], at, length); - - return 0; -} - - -static int iotjs_httpparserwrap_on_header_value(http_parser* parser, - const char* at, size_t length) { - iotjs_httpparserwrap_t* httpparserwrap = - (iotjs_httpparserwrap_t*)(parser->data); - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_httpparserwrap_t, httpparserwrap); - if (_this->n_fields != _this->n_values) { - _this->n_values++; - iotjs_string_make_empty(&_this->values[_this->n_values - 1]); - } - - IOTJS_ASSERT(_this->n_fields == _this->n_values); - - iotjs_string_append(&_this->values[_this->n_values - 1], at, length); - - return 0; -} - - -static int iotjs_httpparserwrap_on_headers_complete(http_parser* parser) { - iotjs_httpparserwrap_t* httpparserwrap = - (iotjs_httpparserwrap_t*)(parser->data); - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_httpparserwrap_t, httpparserwrap); - - const iotjs_jval_t* jobj = iotjs_httpparserwrap_jobject(httpparserwrap); - iotjs_jval_t func = - iotjs_jval_get_property(jobj, IOTJS_MAGIC_STRING_ONHEADERSCOMPLETE); - IOTJS_ASSERT(iotjs_jval_is_function(&func)); - - // URL - iotjs_jargs_t argv = iotjs_jargs_create(1); - iotjs_jval_t info = iotjs_jval_create_object(); - - if (_this->flushed) { - // If some headers already are flushed, - // flush the remaining headers. - // In Flush function, url is already flushed to JS. - iotjs_httpparserwrap_flush(httpparserwrap); - } else { - // Here, there was no flushed header. - // We need to make a new header object with all header fields - iotjs_jval_t jheader = iotjs_httpparserwrap_make_header(httpparserwrap); - iotjs_jval_set_property_jval(&info, IOTJS_MAGIC_STRING_HEADERS, &jheader); - iotjs_jval_destroy(&jheader); - if (_this->parser.type == HTTP_REQUEST) { - IOTJS_ASSERT(!iotjs_string_is_empty(&_this->url)); - iotjs_jval_set_property_string(&info, IOTJS_MAGIC_STRING_URL, - &_this->url); - } - } - _this->n_fields = _this->n_values = 0; - - // Method - if (_this->parser.type == HTTP_REQUEST) { - iotjs_jval_set_property_number(&info, IOTJS_MAGIC_STRING_METHOD, - _this->parser.method); - } - - // Status - if (_this->parser.type == HTTP_RESPONSE) { - iotjs_jval_set_property_number(&info, IOTJS_MAGIC_STRING_STATUS, - _this->parser.status_code); - iotjs_jval_set_property_string(&info, IOTJS_MAGIC_STRING_STATUS_MSG, - &_this->status_msg); - } - - - // For future support, current http_server module does not support - // upgrade and keepalive. - // upgrade - iotjs_jval_set_property_boolean(&info, IOTJS_MAGIC_STRING_UPGRADE, - _this->parser.upgrade); - // shouldkeepalive - iotjs_jval_set_property_boolean(&info, IOTJS_MAGIC_STRING_SHOULDKEEPALIVE, - http_should_keep_alive(&_this->parser)); - - - iotjs_jargs_append_jval(&argv, &info); - - iotjs_jval_t res = iotjs_make_callback_with_result(&func, jobj, &argv); - bool ret = iotjs_jval_as_boolean(&res); - - iotjs_jargs_destroy(&argv); - iotjs_jval_destroy(&func); - iotjs_jval_destroy(&res); - iotjs_jval_destroy(&info); - - return ret; -} - - -static int iotjs_httpparserwrap_on_body(http_parser* parser, const char* at, - size_t length) { - iotjs_httpparserwrap_t* httpparserwrap = - (iotjs_httpparserwrap_t*)(parser->data); - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_httpparserwrap_t, httpparserwrap); - - const iotjs_jval_t* jobj = iotjs_httpparserwrap_jobject(httpparserwrap); - iotjs_jval_t func = iotjs_jval_get_property(jobj, IOTJS_MAGIC_STRING_ONBODY); - IOTJS_ASSERT(iotjs_jval_is_function(&func)); - - iotjs_jargs_t argv = iotjs_jargs_create(3); - iotjs_jargs_append_jval(&argv, _this->cur_jbuf); - iotjs_jargs_append_number(&argv, at - _this->cur_buf); - iotjs_jargs_append_number(&argv, length); - - - iotjs_make_callback(&func, jobj, &argv); - - iotjs_jargs_destroy(&argv); - iotjs_jval_destroy(&func); - - return 0; -} - - -static int iotjs_httpparserwrap_on_message_complete(http_parser* parser) { - iotjs_httpparserwrap_t* httpparserwrap = - (iotjs_httpparserwrap_t*)(parser->data); - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_httpparserwrap_t, - httpparserwrap); - - const iotjs_jval_t* jobj = iotjs_httpparserwrap_jobject(httpparserwrap); - iotjs_jval_t func = - iotjs_jval_get_property(jobj, IOTJS_MAGIC_STRING_ONMESSAGECOMPLETE); - IOTJS_ASSERT(iotjs_jval_is_function(&func)); - - iotjs_make_callback(&func, jobj, iotjs_jargs_get_empty()); - - iotjs_jval_destroy(&func); - - return 0; -} - - -iotjs_jval_t iotjs_httpparserwrap_make_header(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_httpparserwrap_t, httpparserwrap); - - iotjs_jval_t jheader = iotjs_jval_create_array(_this->n_values * 2); - for (size_t i = 0; i < _this->n_values; i++) { - iotjs_jval_t f = iotjs_jval_create_string(&_this->fields[i]); - iotjs_jval_t v = iotjs_jval_create_string(&_this->values[i]); - iotjs_jval_set_property_by_index(&jheader, i * 2, &f); - iotjs_jval_set_property_by_index(&jheader, i * 2 + 1, &v); - iotjs_jval_destroy(&f); - iotjs_jval_destroy(&v); - } - return jheader; -} - - -void iotjs_httpparserwrap_flush(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_httpparserwrap_t, httpparserwrap); - - const iotjs_jval_t* jobj = iotjs_httpparserwrap_jobject(httpparserwrap); - iotjs_jval_t func = - iotjs_jval_get_property(jobj, IOTJS_MAGIC_STRING_ONHEADERS); - IOTJS_ASSERT(iotjs_jval_is_function(&func)); - - iotjs_jargs_t argv = iotjs_jargs_create(2); - iotjs_jval_t jheader = iotjs_httpparserwrap_make_header(httpparserwrap); - iotjs_jargs_append_jval(&argv, &jheader); - iotjs_jval_destroy(&jheader); - if (_this->parser.type == HTTP_REQUEST && - !iotjs_string_is_empty(&_this->url)) { - iotjs_jargs_append_string(&argv, &_this->url); - } - - iotjs_make_callback(&func, jobj, &argv); - - iotjs_string_make_empty(&_this->url); - iotjs_jargs_destroy(&argv); - iotjs_jval_destroy(&func); - _this->flushed = true; -} - - -void iotjs_httpparserwrap_set_buf(THIS, iotjs_jval_t* jbuf, char* buf, - size_t sz) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_httpparserwrap_t, httpparserwrap); - _this->cur_jbuf = jbuf; - _this->cur_buf = buf; - _this->cur_buf_len = sz; -} - - -iotjs_jval_t* iotjs_httpparserwrap_jobject(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_httpparserwrap_t, httpparserwrap); - - return iotjs_jobjectwrap_jobject(&_this->jobjectwrap); -} - - -http_parser* iotjs_httpparserwrap_parser(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_httpparserwrap_t, httpparserwrap); - return &_this->parser; -} - - -#undef THIS - - -const struct http_parser_settings settings = { - iotjs_httpparserwrap_on_message_begin, - iotjs_httpparserwrap_on_url, - iotjs_httpparserwrap_on_status, - iotjs_httpparserwrap_on_header_field, - iotjs_httpparserwrap_on_header_value, - iotjs_httpparserwrap_on_headers_complete, - iotjs_httpparserwrap_on_body, - iotjs_httpparserwrap_on_message_complete, - NULL, /* on_chunk_header */ - NULL, /* on_chunk_complete */ -}; - - -JHANDLER_FUNCTION(Reinitialize) { - JHANDLER_DECLARE_THIS_PTR(httpparserwrap, parser); - DJHANDLER_CHECK_ARGS(1, number); - - http_parser_type httpparser_type = - (http_parser_type)(JHANDLER_GET_ARG(0, number)); - IOTJS_ASSERT(httpparser_type == HTTP_REQUEST || - httpparser_type == HTTP_RESPONSE); - - iotjs_httpparserwrap_initialize(parser, httpparser_type); -} - - -JHANDLER_FUNCTION(Finish) { - JHANDLER_DECLARE_THIS_PTR(httpparserwrap, parser); - DJHANDLER_CHECK_ARGS(0); - - http_parser* nativeparser = iotjs_httpparserwrap_parser(parser); - size_t rv = http_parser_execute(nativeparser, &settings, NULL, 0); - - if (rv != 0) { - enum http_errno err = HTTP_PARSER_ERRNO(nativeparser); - - iotjs_jval_t eobj = iotjs_jval_create_error("Parse Error"); - iotjs_jval_set_property_number(&eobj, IOTJS_MAGIC_STRING_BYTEPARSED, 0); - iotjs_jval_set_property_string_raw(&eobj, IOTJS_MAGIC_STRING_CODE, - http_errno_name(err)); - iotjs_jhandler_return_jval(jhandler, &eobj); - iotjs_jval_destroy(&eobj); - } -} - - -JHANDLER_FUNCTION(Execute) { - JHANDLER_DECLARE_THIS_PTR(httpparserwrap, parser); - DJHANDLER_CHECK_ARGS(1, object); - - const iotjs_jval_t* jbuffer = JHANDLER_GET_ARG(0, object); - iotjs_bufferwrap_t* buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuffer); - char* buf_data = iotjs_bufferwrap_buffer(buffer_wrap); - size_t buf_len = iotjs_bufferwrap_length(buffer_wrap); - JHANDLER_CHECK(buf_data != NULL); - JHANDLER_CHECK(buf_len > 0); - - iotjs_httpparserwrap_set_buf(parser, (iotjs_jval_t*)jbuffer, buf_data, - buf_len); - - http_parser* nativeparser = iotjs_httpparserwrap_parser(parser); - size_t nparsed = - http_parser_execute(nativeparser, &settings, buf_data, buf_len); - - iotjs_httpparserwrap_set_buf(parser, NULL, NULL, 0); - - - if (!nativeparser->upgrade && nparsed != buf_len) { - // nparsed should equal to buf_len except UPGRADE protocol - enum http_errno err = HTTP_PARSER_ERRNO(nativeparser); - iotjs_jval_t eobj = iotjs_jval_create_error("Parse Error"); - iotjs_jval_set_property_number(&eobj, IOTJS_MAGIC_STRING_BYTEPARSED, 0); - iotjs_jval_set_property_string_raw(&eobj, IOTJS_MAGIC_STRING_CODE, - http_errno_name(err)); - iotjs_jhandler_return_jval(jhandler, &eobj); - iotjs_jval_destroy(&eobj); - } else { - iotjs_jhandler_return_number(jhandler, nparsed); - } -} - - -JHANDLER_FUNCTION(Pause) { - JHANDLER_DECLARE_THIS_PTR(httpparserwrap, parser); - DJHANDLER_CHECK_ARGS(0); - - http_parser* nativeparser = iotjs_httpparserwrap_parser(parser); - http_parser_pause(nativeparser, 1); -} - - -JHANDLER_FUNCTION(Resume) { - JHANDLER_DECLARE_THIS_PTR(httpparserwrap, parser); - DJHANDLER_CHECK_ARGS(0); - - http_parser* nativeparser = iotjs_httpparserwrap_parser(parser); - http_parser_pause(nativeparser, 0); -} - - -JHANDLER_FUNCTION(HTTPParserCons) { - DJHANDLER_CHECK_THIS(object); - DJHANDLER_CHECK_ARGS(1, number); - - const iotjs_jval_t* jparser = JHANDLER_GET_THIS(object); - - http_parser_type httpparser_type = - (http_parser_type)(JHANDLER_GET_ARG(0, number)); - IOTJS_ASSERT(httpparser_type == HTTP_REQUEST || - httpparser_type == HTTP_RESPONSE); - iotjs_httpparserwrap_t* parser = - iotjs_httpparserwrap_create(jparser, httpparser_type); - IOTJS_ASSERT(iotjs_jval_is_object(iotjs_httpparserwrap_jobject(parser))); -} - - -iotjs_jval_t InitHttpparser() { - iotjs_jval_t httpparser = iotjs_jval_create_object(); - - iotjs_jval_t jParserCons = - iotjs_jval_create_function_with_dispatch(HTTPParserCons); - iotjs_jval_set_property_jval(&httpparser, IOTJS_MAGIC_STRING_HTTPPARSER, - &jParserCons); - - iotjs_jval_set_property_number(&jParserCons, IOTJS_MAGIC_STRING_REQUEST, - HTTP_REQUEST); - iotjs_jval_set_property_number(&jParserCons, IOTJS_MAGIC_STRING_RESPONSE, - HTTP_RESPONSE); - - iotjs_jval_t methods = iotjs_jval_create_object(); -#define V(num, name, string) \ - iotjs_jval_set_property_string_raw(&methods, #num, #string); - HTTP_METHOD_MAP(V) -#undef V - - iotjs_jval_set_property_jval(&jParserCons, IOTJS_MAGIC_STRING_METHODS, - &methods); - - iotjs_jval_t prototype = iotjs_jval_create_object(); - - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_EXECUTE, Execute); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_REINITIALIZE, - Reinitialize); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_FINISH, Finish); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_PAUSE, Pause); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_RESUME, Resume); - - iotjs_jval_set_property_jval(&jParserCons, IOTJS_MAGIC_STRING_PROTOTYPE, - &prototype); - - iotjs_jval_destroy(&jParserCons); - iotjs_jval_destroy(&methods); - iotjs_jval_destroy(&prototype); - - return httpparser; -} diff --git a/src/modules/iotjs_module_httpparser.h b/src/modules/iotjs_module_httpparser.h deleted file mode 100644 index 34e6881000..0000000000 --- a/src/modules/iotjs_module_httpparser.h +++ /dev/null @@ -1,81 +0,0 @@ -/* Copyright 2015-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_HTTPPARSER_H -#define IOTJS_MODULE_HTTPPARSER_H - - -#include "iotjs_objectwrap.h" - -#include "http_parser.h" - - -// If # of header fields == HEADER_MAX, flush header to JS side. -// This is weired : # of maximum headers in C equals to HEADER_MAX-1. -// This is because , OnHeaders cb, we increase n_fields first, -// and check whether field == HEADER_MAX. -// ex) HEADER_MAX 2 means that we can keep at most 1 header field/value -// during http parsing. -// Increase this to minimize inter JS-C call -#define HEADER_MAX 10 - - -typedef struct { - iotjs_jobjectwrap_t jobjectwrap; - - http_parser parser; - - iotjs_string_t url; - iotjs_string_t status_msg; - - iotjs_string_t fields[HEADER_MAX]; - iotjs_string_t values[HEADER_MAX]; - size_t n_fields; - size_t n_values; - - iotjs_jval_t* cur_jbuf; - char* cur_buf; - size_t cur_buf_len; - - bool flushed; -} IOTJS_VALIDATED_STRUCT(iotjs_httpparserwrap_t); - - -typedef enum http_parser_type http_parser_type; - - -#define THIS iotjs_httpparserwrap_t* httpparserwrap - - -iotjs_httpparserwrap_t* iotjs_httpparserwrap_create(const iotjs_jval_t* jparser, - http_parser_type type); - -void iotjs_httpparserwrap_initialize(THIS, http_parser_type type); -iotjs_jval_t iotjs_httpparserwrap_make_header(THIS); - -void iotjs_httpparserwrap_flush(THIS); - -void iotjs_httpparserwrap_set_buf(THIS, iotjs_jval_t* jbuf, char* buf, - size_t sz); - -iotjs_jval_t* iotjs_httpparserwrap_jobject(THIS); -http_parser* iotjs_httpparserwrap_parser(THIS); - - -#undef THIS - - -#endif /* IOTJS_MODULE_HTTPPARSER_H */ diff --git a/src/modules/iotjs_module_i2c.c b/src/modules/iotjs_module_i2c.c index c247a798cf..00793c9cb3 100644 --- a/src/modules/iotjs_module_i2c.c +++ b/src/modules/iotjs_module_i2c.c @@ -16,314 +16,187 @@ #include "iotjs_def.h" #include "iotjs_module_i2c.h" -#include "iotjs_objectwrap.h" - - -#define THIS iotjs_i2c_reqwrap_t* i2c_reqwrap +#include "iotjs_uv_request.h" IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(i2c); +IOTJS_DEFINE_PERIPH_CREATE_FUNCTION(i2c); -iotjs_i2c_reqwrap_t* iotjs_i2c_reqwrap_create(const iotjs_jval_t* jcallback, - iotjs_i2c_t* i2c, I2cOp op) { - iotjs_i2c_reqwrap_t* i2c_reqwrap = IOTJS_ALLOC(iotjs_i2c_reqwrap_t); - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_i2c_reqwrap_t, i2c_reqwrap); - - iotjs_reqwrap_initialize(&_this->reqwrap, jcallback, (uv_req_t*)&_this->req); - - _this->req_data.op = op; -#if defined(__linux__) || defined(__APPLE__) - _this->req_data.device = iotjs_string_create(""); -#endif - _this->i2c_data = i2c; - return i2c_reqwrap; -} - - -static void iotjs_i2c_reqwrap_destroy(THIS) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_i2c_reqwrap_t, i2c_reqwrap); - iotjs_reqwrap_destroy(&_this->reqwrap); -#if defined(__linux__) || defined(__APPLE__) - iotjs_string_destroy(&_this->req_data.device); -#endif - IOTJS_RELEASE(i2c_reqwrap); -} - - -void iotjs_i2c_reqwrap_dispatched(THIS) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_i2c_reqwrap_t, i2c_reqwrap); - iotjs_i2c_reqwrap_destroy(i2c_reqwrap); +static void iotjs_i2c_destroy(iotjs_i2c_t* i2c) { + iotjs_i2c_destroy_platform_data(i2c->platform_data); + IOTJS_RELEASE(i2c); } - -uv_work_t* iotjs_i2c_reqwrap_req(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_i2c_reqwrap_t, i2c_reqwrap); - return &_this->req; +static void i2c_worker(uv_work_t* work_req) { + iotjs_periph_data_t* worker_data = + (iotjs_periph_data_t*)IOTJS_UV_REQUEST_EXTRA_DATA(work_req); + iotjs_i2c_t* i2c = (iotjs_i2c_t*)worker_data->data; + + switch (worker_data->op) { + case kI2cOpOpen: + worker_data->result = iotjs_i2c_open(i2c); + break; + case kI2cOpWrite: + worker_data->result = iotjs_i2c_write(i2c); + break; + case kI2cOpRead: + worker_data->result = iotjs_i2c_read(i2c); + break; + case kI2cOpClose: + worker_data->result = iotjs_i2c_close(i2c); + break; + default: + IOTJS_ASSERT(!"Invalid Operation"); + } } +JS_FUNCTION(i2c_constructor) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(1, object); + DJS_CHECK_ARG_IF_EXIST(1, function); -const iotjs_jval_t* iotjs_i2c_reqwrap_jcallback(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_i2c_reqwrap_t, i2c_reqwrap); - return iotjs_reqwrap_jcallback(&_this->reqwrap); -} + // Create I2C object + const jerry_value_t ji2c = JS_GET_THIS(); + iotjs_i2c_t* i2c = i2c_create(ji2c); + jerry_value_t jconfig; + JS_GET_REQUIRED_ARG_VALUE(0, jconfig, IOTJS_MAGIC_STRING_CONFIG, object); -iotjs_i2c_reqwrap_t* iotjs_i2c_reqwrap_from_request(uv_work_t* req) { - return (iotjs_i2c_reqwrap_t*)(iotjs_reqwrap_from_request((uv_req_t*)req)); -} + jerry_value_t res = iotjs_i2c_set_platform_config(i2c, jconfig); + if (jerry_value_is_error(res)) { + return res; + } + JS_GET_REQUIRED_CONF_VALUE(jconfig, i2c->address, IOTJS_MAGIC_STRING_ADDRESS, + number); -iotjs_i2c_reqdata_t* iotjs_i2c_reqwrap_data(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_i2c_reqwrap_t, i2c_reqwrap); - return &_this->req_data; -} + jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(1, function); + // If the callback doesn't exist, it is completed synchronously. + // Otherwise, it will be executed asynchronously. + if (!jerry_value_is_null(jcallback)) { + iotjs_periph_call_async(i2c, jcallback, kI2cOpOpen, i2c_worker); + } else if (!iotjs_i2c_open(i2c)) { + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kI2cOpOpen)); + } -iotjs_i2c_t* iotjs_i2c_instance_from_reqwrap(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_i2c_reqwrap_t, i2c_reqwrap); - return _this->i2c_data; + return jerry_create_undefined(); } -#undef THIS - +JS_FUNCTION(i2c_close) { + JS_DECLARE_THIS_PTR(i2c, i2c); + DJS_CHECK_ARG_IF_EXIST(1, function); -iotjs_i2c_t* iotjs_i2c_create(const iotjs_jval_t* ji2c) { - iotjs_i2c_t* i2c = IOTJS_ALLOC(iotjs_i2c_t); - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_i2c_t, i2c); + iotjs_periph_call_async(i2c, JS_GET_ARG_IF_EXIST(0, function), kI2cOpClose, + i2c_worker); -#if defined(__linux__) - _this->device_fd = -1; -#elif defined(__NUTTX__) - _this->i2c_master = NULL; -#endif - - iotjs_jobjectwrap_initialize(&_this->jobjectwrap, ji2c, - &this_module_native_info); - return i2c; + return jerry_create_undefined(); } +JS_FUNCTION(i2c_close_sync) { + JS_DECLARE_THIS_PTR(i2c, i2c); -static void iotjs_i2c_destroy(iotjs_i2c_t* i2c) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_i2c_t, i2c); - iotjs_jobjectwrap_destroy(&_this->jobjectwrap); - IOTJS_RELEASE(i2c); -} - + if (!iotjs_i2c_close(i2c)) { + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kI2cOpClose)); + } -iotjs_i2c_t* iotjs_i2c_instance_from_jval(const iotjs_jval_t* ji2c) { - iotjs_jobjectwrap_t* jobjectwrap = iotjs_jobjectwrap_from_jobject(ji2c); - return (iotjs_i2c_t*)jobjectwrap; + return jerry_create_undefined(); } +static jerry_value_t i2c_write_helper(iotjs_i2c_t* i2c, + const jerry_value_t jargv[], + const jerry_length_t jargc, bool async) { + jerry_value_t jarray; + JS_GET_REQUIRED_ARG_VALUE(0, jarray, IOTJS_MAGIC_STRING_DATA, array); -void AfterI2CWork(uv_work_t* work_req, int status) { - iotjs_i2c_reqwrap_t* req_wrap = iotjs_i2c_reqwrap_from_request(work_req); - iotjs_i2c_reqdata_t* req_data = iotjs_i2c_reqwrap_data(req_wrap); + // Set buffer length and data from jarray + i2c->buf_len = jerry_get_array_length(jarray); + i2c->buf_data = iotjs_buffer_allocate_from_number_array(i2c->buf_len, jarray); - iotjs_jargs_t jargs = iotjs_jargs_create(2); - - if (status) { - iotjs_jval_t error = iotjs_jval_create_error("System error"); - iotjs_jargs_append_jval(&jargs, &error); - iotjs_jval_destroy(&error); + if (async) { + DJS_CHECK_ARG_IF_EXIST(1, function); + iotjs_periph_call_async(i2c, JS_GET_ARG_IF_EXIST(1, function), kI2cOpWrite, + i2c_worker); } else { - switch (req_data->op) { - case kI2cOpOpen: { - if (req_data->error == kI2cErrOpen) { - iotjs_jval_t error = - iotjs_jval_create_error("Failed to open I2C device"); - iotjs_jargs_append_jval(&jargs, &error); - iotjs_jval_destroy(&error); - } else { - iotjs_jargs_append_null(&jargs); - } - break; - } - case kI2cOpWrite: { - if (req_data->error == kI2cErrWrite) { - iotjs_jval_t error = - iotjs_jval_create_error("Cannot write to device"); - iotjs_jargs_append_jval(&jargs, &error); - iotjs_jval_destroy(&error); - } else { - iotjs_jargs_append_null(&jargs); - } - break; - } - case kI2cOpRead: { - if (req_data->error == kI2cErrRead) { - iotjs_jval_t error = - iotjs_jval_create_error("Cannot read from device"); - iotjs_jargs_append_jval(&jargs, &error); - iotjs_jargs_append_null(&jargs); - iotjs_jval_destroy(&error); - } else { - iotjs_jargs_append_null(&jargs); - iotjs_jval_t result = - iotjs_jval_create_byte_array(req_data->buf_len, - req_data->buf_data); - iotjs_jargs_append_jval(&jargs, &result); - iotjs_jval_destroy(&result); - - if (req_data->delay > 0) { - uv_sleep(req_data->delay); - } - - if (req_data->buf_data != NULL) { - iotjs_buffer_release(req_data->buf_data); - } - } - break; - } - default: { - IOTJS_ASSERT(!"Unreachable"); - break; - } + if (!iotjs_i2c_write(i2c)) { + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kI2cOpWrite)); } } - const iotjs_jval_t* jcallback = iotjs_i2c_reqwrap_jcallback(req_wrap); - iotjs_make_callback(jcallback, iotjs_jval_get_undefined(), &jargs); - - iotjs_jargs_destroy(&jargs); - iotjs_i2c_reqwrap_dispatched(req_wrap); + return jerry_create_undefined(); } +typedef enum { IOTJS_I2C_WRITE, IOTJS_I2C_WRITESYNC } iotjs_i2c_op_t; -static void GetI2cArray(const iotjs_jval_t* jarray, - iotjs_i2c_reqdata_t* req_data) { - // FIXME - // Need to implement a function to get array info from iotjs_jval_t Array. - iotjs_jval_t jlength = - iotjs_jval_get_property(jarray, IOTJS_MAGIC_STRING_LENGTH); - IOTJS_ASSERT(!iotjs_jval_is_undefined(&jlength)); - - req_data->buf_len = iotjs_jval_as_number(&jlength); - req_data->buf_data = iotjs_buffer_allocate(req_data->buf_len); - - for (uint8_t i = 0; i < req_data->buf_len; i++) { - iotjs_jval_t jdata = iotjs_jval_get_property_by_index(jarray, i); - req_data->buf_data[i] = iotjs_jval_as_number(&jdata); - iotjs_jval_destroy(&jdata); - } - - iotjs_jval_destroy(&jlength); +static jerry_value_t i2c_do_write_or_writesync(const jerry_value_t jfunc, + const jerry_value_t jthis, + const jerry_value_t jargv[], + const jerry_length_t jargc, + const iotjs_i2c_op_t i2c_op) { + JS_DECLARE_THIS_PTR(i2c, i2c); + DJS_CHECK_ARGS(1, array); + return i2c_write_helper(i2c, jargv, jargc, i2c_op == IOTJS_I2C_WRITE); } - -#define I2C_ASYNC(op) \ - do { \ - uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get()); \ - uv_work_t* req = iotjs_i2c_reqwrap_req(req_wrap); \ - uv_queue_work(loop, req, op##Worker, AfterI2CWork); \ - } while (0) - - -JHANDLER_FUNCTION(I2cCons) { - DJHANDLER_CHECK_THIS(object); -#if defined(__linux__) || defined(__APPLE__) - DJHANDLER_CHECK_ARGS(2, string, function); - iotjs_string_t device = JHANDLER_GET_ARG(0, string); -#elif defined(__NUTTX__) - DJHANDLER_CHECK_ARGS(2, number, function); - int device = JHANDLER_GET_ARG(0, number); -#endif - - // Create I2C object - const iotjs_jval_t* ji2c = JHANDLER_GET_THIS(object); - iotjs_i2c_t* i2c = iotjs_i2c_create(ji2c); - IOTJS_ASSERT(i2c == - (iotjs_i2c_t*)(iotjs_jval_get_object_native_handle(ji2c))); - - // Create I2C request wrap - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG(1, function); - iotjs_i2c_reqwrap_t* req_wrap = - iotjs_i2c_reqwrap_create(jcallback, i2c, kI2cOpOpen); - - iotjs_i2c_reqdata_t* req_data = iotjs_i2c_reqwrap_data(req_wrap); -#if defined(__linux__) || defined(__APPLE__) - iotjs_string_append(&req_data->device, iotjs_string_data(&device), - iotjs_string_size(&device)); -#elif defined(__NUTTX__) - req_data->device = device; -#endif - - I2C_ASYNC(Open); +JS_FUNCTION(i2c_write) { + return i2c_do_write_or_writesync(jfunc, jthis, jargv, jargc, IOTJS_I2C_WRITE); } - -JHANDLER_FUNCTION(SetAddress) { - JHANDLER_DECLARE_THIS_PTR(i2c, i2c); - DJHANDLER_CHECK_ARGS(1, number); - - I2cSetAddress(i2c, JHANDLER_GET_ARG(0, number)); - - iotjs_jhandler_return_null(jhandler); +JS_FUNCTION(i2c_write_sync) { + return i2c_do_write_or_writesync(jfunc, jthis, jargv, jargc, + IOTJS_I2C_WRITESYNC); } +JS_FUNCTION(i2c_read) { + JS_DECLARE_THIS_PTR(i2c, i2c); + DJS_CHECK_ARGS(1, number); + DJS_CHECK_ARG_IF_EXIST(1, function); -JHANDLER_FUNCTION(Close) { - JHANDLER_DECLARE_THIS_PTR(i2c, i2c); - DJHANDLER_CHECK_ARGS(0); + JS_GET_REQUIRED_ARG_VALUE(0, i2c->buf_len, IOTJS_MAGIC_STRING_LENGTH, number); - I2cClose(i2c); + iotjs_periph_call_async(i2c, JS_GET_ARG_IF_EXIST(1, function), kI2cOpRead, + i2c_worker); - iotjs_jhandler_return_null(jhandler); + return jerry_create_undefined(); } +JS_FUNCTION(i2c_read_sync) { + JS_DECLARE_THIS_PTR(i2c, i2c); + DJS_CHECK_ARGS(1, number); -JHANDLER_FUNCTION(Write) { - JHANDLER_DECLARE_THIS_PTR(i2c, i2c); - DJHANDLER_CHECK_ARGS(2, array, function); + JS_GET_REQUIRED_ARG_VALUE(0, i2c->buf_len, IOTJS_MAGIC_STRING_LENGTH, number); - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG(1, function); - - iotjs_i2c_reqwrap_t* req_wrap = - iotjs_i2c_reqwrap_create(jcallback, i2c, kI2cOpWrite); - iotjs_i2c_reqdata_t* req_data = iotjs_i2c_reqwrap_data(req_wrap); - - GetI2cArray(JHANDLER_GET_ARG(0, array), req_data); - - I2C_ASYNC(Write); - - iotjs_jhandler_return_null(jhandler); -} - - -JHANDLER_FUNCTION(Read) { - JHANDLER_DECLARE_THIS_PTR(i2c, i2c); - DJHANDLER_CHECK_ARGS(2, number, function); - - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG(1, function); - - iotjs_i2c_reqwrap_t* req_wrap = - iotjs_i2c_reqwrap_create(jcallback, i2c, kI2cOpRead); - - iotjs_i2c_reqdata_t* req_data = iotjs_i2c_reqwrap_data(req_wrap); - req_data->buf_len = JHANDLER_GET_ARG(0, number); - req_data->delay = 0; + 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)); + } - I2C_ASYNC(Read); + IOTJS_RELEASE(i2c->buf_data); - iotjs_jhandler_return_null(jhandler); + return result; } +jerry_value_t iotjs_init_i2c(void) { + jerry_value_t ji2c_cons = jerry_create_external_function(i2c_constructor); -iotjs_jval_t InitI2c() { - iotjs_jval_t jI2cCons = iotjs_jval_create_function_with_dispatch(I2cCons); - - iotjs_jval_t prototype = iotjs_jval_create_object(); + jerry_value_t prototype = jerry_create_object(); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_SETADDRESS, SetAddress); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_CLOSE, Close); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_WRITE, Write); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_READ, Read); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_CLOSE, i2c_close); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_CLOSESYNC, + i2c_close_sync); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_WRITE, i2c_write); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_WRITESYNC, + i2c_write_sync); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_READ, i2c_read); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_READSYNC, i2c_read_sync); - iotjs_jval_set_property_jval(&jI2cCons, IOTJS_MAGIC_STRING_PROTOTYPE, - &prototype); + iotjs_jval_set_property_jval(ji2c_cons, IOTJS_MAGIC_STRING_PROTOTYPE, + prototype); - iotjs_jval_destroy(&prototype); + jerry_release_value(prototype); - return jI2cCons; + return ji2c_cons; } diff --git a/src/modules/iotjs_module_i2c.h b/src/modules/iotjs_module_i2c.h index 6cba4e9695..6844071d07 100644 --- a/src/modules/iotjs_module_i2c.h +++ b/src/modules/iotjs_module_i2c.h @@ -18,87 +18,31 @@ #define IOTJS_MODULE_I2C_H #include "iotjs_def.h" -#include "iotjs_objectwrap.h" -#include "iotjs_reqwrap.h" - -#if defined(__NUTTX__) -#include -#endif - -typedef enum { - kI2cOpSetAddress, - kI2cOpOpen, - kI2cOpClose, - kI2cOpWrite, - kI2cOpRead, -} I2cOp; - -typedef enum { - kI2cErrOk = 0, - kI2cErrOpen = -1, - kI2cErrRead = -2, - kI2cErrWrite = -3, -} I2cError; - - -typedef struct { -#if defined(__linux__) || defined(__APPLE__) - iotjs_string_t device; -#elif defined(__NUTTX__) - int device; -#endif - char* buf_data; - uint8_t buf_len; - uint8_t byte; - uint8_t cmd; - int32_t delay; - - I2cOp op; - I2cError error; -} iotjs_i2c_reqdata_t; - +#include "iotjs_module_periph_common.h" +// Forward declaration of platform data. These are only used by platform code. +// Generic I2C module never dereferences platform data pointer. +typedef struct iotjs_i2c_platform_data_s iotjs_i2c_platform_data_t; // This I2c class provides interfaces for I2C operation. typedef struct { - iotjs_jobjectwrap_t jobjectwrap; -#if defined(__linux__) - int device_fd; - uint8_t addr; -#elif defined(__NUTTX__) - struct i2c_master_s* i2c_master; - struct i2c_config_s config; -#endif -} IOTJS_VALIDATED_STRUCT(iotjs_i2c_t); - - -typedef struct { - iotjs_reqwrap_t reqwrap; - uv_work_t req; - iotjs_i2c_reqdata_t req_data; - iotjs_i2c_t* i2c_data; -} IOTJS_VALIDATED_STRUCT(iotjs_i2c_reqwrap_t); - - -iotjs_i2c_t* iotjs_i2c_create(const iotjs_jval_t* ji2c); -iotjs_i2c_t* iotjs_i2c_instance_from_jval(const iotjs_jval_t* ji2c); - -#define THIS iotjs_i2c_reqwrap_t* i2c_reqwrap -iotjs_i2c_reqwrap_t* iotjs_i2c_reqwrap_create(const iotjs_jval_t* jcallback, - iotjs_i2c_t* i2c, I2cOp op); -void iotjs_i2c_reqwrap_dispatched(THIS); -uv_work_t* iotjs_i2c_reqwrap_req(THIS); -const iotjs_jval_t* iotjs_i2c_reqwrap_jcallback(THIS); -iotjs_i2c_reqwrap_t* iotjs_i2c_reqwrap_from_request(uv_work_t* req); -iotjs_i2c_reqdata_t* iotjs_i2c_reqwrap_data(THIS); -iotjs_i2c_t* iotjs_i2c_instance_from_reqwrap(THIS); -#undef THIS - - -void I2cSetAddress(iotjs_i2c_t* i2c, uint8_t address); -void OpenWorker(uv_work_t* work_req); -void I2cClose(iotjs_i2c_t* i2c); -void WriteWorker(uv_work_t* work_req); -void ReadWorker(uv_work_t* work_req); + jerry_value_t jobject; + iotjs_i2c_platform_data_t* platform_data; + char* buf_data; + uint8_t buf_len; + uint8_t address; +} iotjs_i2c_t; + +jerry_value_t iotjs_i2c_set_platform_config(iotjs_i2c_t* i2c, + const jerry_value_t jconfig); +bool iotjs_i2c_open(iotjs_i2c_t* i2c); +bool iotjs_i2c_write(iotjs_i2c_t* i2c); +bool iotjs_i2c_read(iotjs_i2c_t* i2c); +bool iotjs_i2c_close(iotjs_i2c_t* i2c); + +// Platform-related functions; they are implemented +// by platform code (i.e.: linux, nuttx, tizen). +void iotjs_i2c_create_platform_data(iotjs_i2c_t* i2c); +void iotjs_i2c_destroy_platform_data(iotjs_i2c_platform_data_t* platform_data); #endif /* IOTJS_MODULE_I2C_H */ diff --git a/src/modules/iotjs_module_mqtt.c b/src/modules/iotjs_module_mqtt.c new file mode 100644 index 0000000000..a825719c1a --- /dev/null +++ b/src/modules/iotjs_module_mqtt.c @@ -0,0 +1,857 @@ +/* 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 +#include + +#include "iotjs_def.h" +#include "iotjs_module_buffer.h" +#include "iotjs_module_mqtt.h" + +IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(mqttclient); + +static void iotjs_mqttclient_destroy(iotjs_mqttclient_t *mqttclient) { + IOTJS_RELEASE(mqttclient->buffer); + IOTJS_RELEASE(mqttclient); +} + +iotjs_mqttclient_t *iotjs_mqttclient_create(const jerry_value_t jobject) { + iotjs_mqttclient_t *mqttclient = IOTJS_ALLOC(iotjs_mqttclient_t); + + jerry_set_object_native_pointer(jobject, mqttclient, + &this_module_native_info); + return mqttclient; +} + + +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, + uint32_t *out_length) { + // There must be at least 2 bytes to decode + uint32_t c = (uint32_t)(*buffer); + uint32_t decoded_length = (c & 0x7F); + uint32_t length = 1; + uint32_t shift = 7; + + buffer++; + + do { + if (++length > IOTJS_MODULE_MQTT_MAX_REMAINING_LENGTH_BYTES) { + return 0; + } + c = (uint32_t)(*buffer); + decoded_length += (c & 0x7F) << shift; + + shift += 7; + buffer++; + } while ((c & 0x80) != 0); + + if (c == 0) { + // The length must be encoded with the least amount of bytes. + // This rule is not fulfilled if the last byte is zero. + return 0; + } + + *out_length = length; + return decoded_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_tmp_buffer_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_mqtt_ack(char *buffer, char *name, jerry_value_t jsref, + char *error) { + uint16_t package_id = + iotjs_mqtt_calculate_length((uint8_t)buffer[0], (uint8_t)buffer[1]); + + // The callback takes the packet identifier as parameter. + jerry_value_t args[2] = { jerry_create_number(package_id), + jerry_create_undefined() }; + + if (error) { + args[1] = iotjs_jval_create_error_without_error_flag(error); + } + + jerry_value_t fn = iotjs_jval_get_property(jsref, name); + iotjs_invoke_callback(fn, jsref, args, 2); + jerry_release_value(fn); + jerry_release_value(args[0]); + jerry_release_value(args[1]); +} + + +JS_FUNCTION(mqtt_init) { + DJS_CHECK_THIS(); + + const jerry_value_t jmqtt = JS_GET_ARG(0, object); + + iotjs_mqttclient_t *mqttclient = iotjs_mqttclient_create(jmqtt); + mqttclient->buffer = NULL; + mqttclient->buffer_length = 0; + + return jerry_create_undefined(); +} + + +JS_FUNCTION(mqtt_connect) { + DJS_CHECK_THIS(); + + DJS_CHECK_ARGS(1, object); + + jerry_value_t joptions = JS_GET_ARG(0, object); + + iotjs_tmp_buffer_t client_id; + iotjs_jval_get_jproperty_as_tmp_buffer(joptions, IOTJS_MAGIC_STRING_CLIENTID, + &client_id); + iotjs_tmp_buffer_t username; + iotjs_jval_get_jproperty_as_tmp_buffer(joptions, IOTJS_MAGIC_STRING_USERNAME, + &username); + iotjs_tmp_buffer_t password; + iotjs_jval_get_jproperty_as_tmp_buffer(joptions, IOTJS_MAGIC_STRING_PASSWORD, + &password); + iotjs_tmp_buffer_t message; + iotjs_jval_get_jproperty_as_tmp_buffer(joptions, IOTJS_MAGIC_STRING_MESSAGE, + &message); + iotjs_tmp_buffer_t topic; + iotjs_jval_get_jproperty_as_tmp_buffer(joptions, IOTJS_MAGIC_STRING_TOPIC, + &topic); + + if (client_id.buffer == NULL || client_id.length >= UINT16_MAX || + username.length >= UINT16_MAX || password.length >= UINT16_MAX || + message.length >= UINT16_MAX || topic.length >= UINT16_MAX) { + iotjs_free_tmp_buffer(&client_id); + iotjs_free_tmp_buffer(&username); + iotjs_free_tmp_buffer(&password); + iotjs_free_tmp_buffer(&message); + iotjs_free_tmp_buffer(&topic); + return JS_CREATE_ERROR(COMMON, "mqtt id too long (max: 65535)"); + } + + 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 jretain = + iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_RETAIN); + + uint8_t connect_flags = 0; + connect_flags |= MQTT_FLAG_CLEANSESSION; + + 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_number(jqos)) { + double qos = jerry_get_number_value(jqos); + + if (qos == 1.0) { + connect_flags |= MQTT_FLAG_WILLQOS_1; + } else if (qos == 2.0) { + connect_flags |= MQTT_FLAG_WILLQOS_2; + } + } + + if (!jerry_value_is_undefined(jretain) && + jerry_get_boolean_value(jretain)) { + connect_flags |= MQTT_FLAG_WILLRETAIN; + } + } + + if (username.buffer != NULL) { + connect_flags |= MQTT_FLAG_USERNAME; + } + if (password.buffer != NULL) { + connect_flags |= MQTT_FLAG_PASSWORD; + } + + uint16_t keepalive = 0; + + if (jerry_value_is_number(jkeepalive)) { + keepalive = (uint16_t)jerry_get_number_value(jkeepalive); + } + + if (keepalive < 30) { + keepalive = 30; + } + + 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) + IOTJS_MQTT_LSB_MSB_SIZE; + + size_t payload_len = IOTJS_MQTT_LSB_MSB_SIZE + client_id.length; + + 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++ = (uint8_t)(keepalive >> 8); + *buff_ptr++ = (uint8_t)(keepalive & 0x00FF); + + 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); + } + + iotjs_free_tmp_buffer(&client_id); + iotjs_free_tmp_buffer(&username); + iotjs_free_tmp_buffer(&password); + iotjs_free_tmp_buffer(&message); + iotjs_free_tmp_buffer(&topic); + + jerry_release_value(jkeepalive); + jerry_release_value(jwill); + jerry_release_value(jqos); + jerry_release_value(jretain); + + return jbuff; +} + + +JS_FUNCTION(mqtt_publish) { + DJS_CHECK_THIS(); + + DJS_CHECK_ARGS(3, any, any, number); + + iotjs_tmp_buffer_t topic; + iotjs_jval_as_tmp_buffer(JS_GET_ARG(0, any), &topic); + + if (jerry_value_is_error(topic.jval)) { + return topic.jval; + } + + if (topic.buffer == NULL || topic.length >= UINT16_MAX) { + iotjs_free_tmp_buffer(&topic); + + return JS_CREATE_ERROR(COMMON, "Topic for PUBLISH is empty or too long."); + } + + iotjs_tmp_buffer_t message; + iotjs_jval_as_tmp_buffer(JS_GET_ARG(1, any), &message); + + if (jerry_value_is_error(message.jval)) { + iotjs_free_tmp_buffer(&topic); + return message.jval; + } + + // header bits: | 16 bit packet id | 4 bit PUBLISH header | + uint32_t header = (uint32_t)JS_GET_ARG(2, number); + uint32_t packet_identifier = (header >> 4); + + uint8_t header_byte = 0; + header_byte |= (PUBLISH << 4) | (header & 0xf); + + const uint8_t qos_mask = (0x3 << 1); + + size_t payload_len = message.length + IOTJS_MQTT_LSB_MSB_SIZE; + size_t variable_header_len = topic.length + IOTJS_MQTT_LSB_MSB_SIZE; + + if (header_byte & qos_mask) { + variable_header_len += IOTJS_MQTT_LSB_MSB_SIZE; + } + + 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); + + if (header_byte & qos_mask) { + // Packet id format is MSB / LSB. + *buff_ptr++ = (uint8_t)(packet_identifier >> 8); + *buff_ptr++ = (uint8_t)(packet_identifier & 0x00FF); + } + + // 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.buffer, message.length); + + iotjs_free_tmp_buffer(&message); + iotjs_free_tmp_buffer(&topic); + return jbuff; +} + + +static int iotjs_mqtt_handle(jerry_value_t jsref, char first_byte, char *buffer, + uint32_t packet_size) { + char packet_type = (first_byte >> 4) & 0x0F; + + switch (packet_type) { + case CONNACK: { + if (packet_size != 2) { + return MQTT_ERR_CORRUPTED_PACKET; + } + + uint8_t return_code = (uint8_t)buffer[1]; + + if (return_code != 0) { + return return_code; + } + + jerry_value_t fn = + iotjs_jval_get_property(jsref, IOTJS_MAGIC_STRING_ONCONNECTION); + iotjs_invoke_callback(fn, jsref, NULL, 0); + + jerry_release_value(fn); + break; + } + case PUBLISH: { + mqtt_header_t 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[0]; + uint8_t topic_length_lsb = (uint8_t)buffer[1]; + buffer += 2; + + uint16_t topic_length = + iotjs_mqtt_calculate_length(topic_length_msb, topic_length_lsb); + + if (!jerry_is_valid_utf8_string((const uint8_t *)buffer, topic_length)) { + return MQTT_ERR_CORRUPTED_PACKET; + } + + const jerry_char_t *topic = (const jerry_char_t *)buffer; + jerry_value_t jtopic = jerry_create_string_sz(topic, topic_length); + buffer += 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 = (uint8_t)buffer[0]; + uint8_t packet_identifier_lsb = (uint8_t)buffer[1]; + buffer += 2; + + packet_identifier = iotjs_mqtt_calculate_length(packet_identifier_msb, + packet_identifier_lsb); + } + + size_t payload_length = + (size_t)packet_size - 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); + + memcpy(msg_wrap->buffer, buffer, payload_length); + + jerry_value_t args[4] = { jmessage, jtopic, + jerry_create_number(header.bits.qos), + jerry_create_number(packet_identifier) }; + + jerry_value_t fn = + iotjs_jval_get_property(jsref, IOTJS_MAGIC_STRING_ONMESSAGE); + iotjs_invoke_callback(fn, jsref, args, 4); + jerry_release_value(fn); + + for (uint8_t i = 0; i < 4; i++) { + jerry_release_value(args[i]); + } + + break; + } + case PUBACK: { + if (packet_size != 2 || (first_byte & 0x0F) != 0x0) { + return MQTT_ERR_CORRUPTED_PACKET; + } + + iotjs_mqtt_ack(buffer, IOTJS_MAGIC_STRING_ONACK, jsref, NULL); + break; + } + case PUBREC: { + if (packet_size != 2 || (first_byte & 0x0F) != 0x0) { + return MQTT_ERR_CORRUPTED_PACKET; + } + + iotjs_mqtt_ack(buffer, IOTJS_MAGIC_STRING_ONPUBREC, jsref, NULL); + break; + } + case PUBREL: { + if (packet_size != 2 || (first_byte & 0x0F) != 0x2) { + return MQTT_ERR_CORRUPTED_PACKET; + } + + iotjs_mqtt_ack(buffer, IOTJS_MAGIC_STRING_ONPUBREL, jsref, NULL); + break; + } + case PUBCOMP: { + if (packet_size != 2 || (first_byte & 0x0F) != 0x0) { + return MQTT_ERR_CORRUPTED_PACKET; + } + + iotjs_mqtt_ack(buffer, IOTJS_MAGIC_STRING_ONACK, jsref, NULL); + break; + } + case SUBACK: { + // We assume that only one topic was in the SUBSCRIBE packet. + if (packet_size != 3 || (first_byte & 0x0F) != 0x0) { + return MQTT_ERR_CORRUPTED_PACKET; + } + + char *error = NULL; + + if ((uint8_t)buffer[2] == 0x80) { + error = "Subscribe failed"; + } + + iotjs_mqtt_ack(buffer, IOTJS_MAGIC_STRING_ONACK, jsref, error); + break; + } + case UNSUBACK: { + if (packet_size != 2 || (first_byte & 0x0F) != 0x0) { + return MQTT_ERR_CORRUPTED_PACKET; + } + + iotjs_mqtt_ack(buffer, IOTJS_MAGIC_STRING_ONACK, jsref, NULL); + break; + } + case PINGRESP: { + if (packet_size != 0 || (first_byte & 0x0F) != 0x0) { + return MQTT_ERR_CORRUPTED_PACKET; + } + + jerry_value_t fn = + iotjs_jval_get_property(jsref, IOTJS_MAGIC_STRING_ONPINGRESP); + iotjs_invoke_callback(fn, jsref, NULL, 0); + jerry_release_value(fn); + break; + } + case DISCONNECT: { + if (packet_size != 0 || (first_byte & 0x0F) != 0x0) { + return MQTT_ERR_CORRUPTED_PACKET; + } + + jerry_value_t fn = + iotjs_jval_get_property(jsref, IOTJS_MAGIC_STRING_ONEND); + iotjs_invoke_callback(fn, jsref, NULL, 0); + jerry_release_value(fn); + break; + } + + case CONNECT: + case SUBSCRIBE: + case UNSUBSCRIBE: + case PINGREQ: + return MQTT_ERR_UNALLOWED_PACKET; + } + + return 0; +} + + +static void iotjs_mqtt_concat_buffers(iotjs_mqttclient_t *mqttclient, + iotjs_bufferwrap_t *buff_recv) { + char *tmp_buf = mqttclient->buffer; + mqttclient->buffer = + IOTJS_CALLOC(mqttclient->buffer_length + buff_recv->length, char); + memcpy(mqttclient->buffer, tmp_buf, mqttclient->buffer_length); + memcpy(mqttclient->buffer + mqttclient->buffer_length, buff_recv->buffer, + buff_recv->length); + mqttclient->buffer_length += buff_recv->length; + IOTJS_RELEASE(tmp_buf); +} + + +static jerry_value_t iotjs_mqtt_handle_error( + iotjs_mqtt_packet_error_t error_code) { + switch (error_code) { + case MQTT_ERR_UNACCEPTABLE_PROTOCOL: + return JS_CREATE_ERROR(COMMON, + "MQTT: Connection refused: unacceptable protocol"); + case MQTT_ERR_BAD_IDENTIFIER: + return JS_CREATE_ERROR(COMMON, + "MQTT: Connection refused: bad client identifier"); + case MQTT_ERR_SERVER_UNAVIABLE: + return JS_CREATE_ERROR(COMMON, + "MQTT: Connection refused: server unavailable"); + case MQTT_ERR_BAD_CREDENTIALS: + return JS_CREATE_ERROR( + COMMON, "MQTT: Connection refused: bad username or password"); + case MQTT_ERR_UNAUTHORISED: + return JS_CREATE_ERROR(COMMON, "MQTT: Connection refused: unauthorised"); + case MQTT_ERR_CORRUPTED_PACKET: + return JS_CREATE_ERROR(COMMON, "MQTT: Corrupted packet"); + case MQTT_ERR_UNALLOWED_PACKET: + return JS_CREATE_ERROR(COMMON, "MQTT: Broker sent an unallowed packet"); + case MQTT_ERR_SUBSCRIPTION_FAILED: + return JS_CREATE_ERROR(COMMON, "MQTT: Subscription failed"); + default: + return JS_CREATE_ERROR(COMMON, "MQTT: Unknown error"); + } +} + + +JS_FUNCTION(mqtt_receive) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(2, object, object); + + jerry_value_t jnat = JS_GET_ARG(0, object); + + iotjs_mqttclient_t *mqttclient = NULL; + if (!jerry_get_object_native_pointer(jnat, (void **)&mqttclient, + &this_module_native_info)) { + return JS_CREATE_ERROR(COMMON, "MQTT native pointer not available"); + } + + jerry_value_t jbuffer = JS_GET_ARG(1, object); + iotjs_bufferwrap_t *buff_recv = iotjs_bufferwrap_from_jbuffer(jbuffer); + if (buff_recv->length == 0) { + return jerry_create_undefined(); + } + + char *current_buffer = buff_recv->buffer; + char *current_buffer_end = current_buffer + buff_recv->length; + + // Concat the buffers if we previously needed to + if (mqttclient->buffer_length > 0) { + iotjs_mqtt_concat_buffers(mqttclient, buff_recv); + current_buffer = mqttclient->buffer; + current_buffer_end = current_buffer + mqttclient->buffer_length; + } + + // Keep on going, if data remains just continue looping + while (true) { + if (current_buffer >= current_buffer_end) { + if (mqttclient->buffer_length > 0) { + IOTJS_RELEASE(mqttclient->buffer); + mqttclient->buffer_length = 0; + } + return jerry_create_undefined(); + } + + if (current_buffer + 2 > current_buffer_end) { + break; + } + + uint32_t packet_size; + uint32_t packet_size_length; + + if ((uint8_t)current_buffer[1] <= 0x7f) { + packet_size = (uint32_t)current_buffer[1]; + packet_size_length = 1; + + if (current_buffer + 2 + packet_size > current_buffer_end) { + break; + } + } else { + // At least 128 bytes arrived + if (current_buffer + 5 >= current_buffer_end) { + break; + } + + packet_size = iotjs_decode_remaining_length(current_buffer + 1, + &packet_size_length); + + if (packet_size == 0) { + return iotjs_mqtt_handle_error(MQTT_ERR_CORRUPTED_PACKET); + } + + if (current_buffer + 1 + packet_size_length + packet_size > + current_buffer_end) { + break; + } + } + + char first_byte = current_buffer[0]; + current_buffer += 1 + packet_size_length; + + int ret_val = + iotjs_mqtt_handle(jnat, first_byte, current_buffer, packet_size); + + if (ret_val != 0) { + return iotjs_mqtt_handle_error(ret_val); + } + + current_buffer += packet_size; + } + + if (current_buffer == mqttclient->buffer) { + return jerry_create_undefined(); + } + + uint32_t remaining_size = (uint32_t)(current_buffer_end - current_buffer); + char *buffer = IOTJS_CALLOC(remaining_size, char); + memcpy(buffer, current_buffer, remaining_size); + + if (mqttclient->buffer != NULL) { + IOTJS_RELEASE(mqttclient->buffer); + } + + mqttclient->buffer = buffer; + mqttclient->buffer_length = remaining_size; + + return jerry_create_undefined(); +} + +static jerry_value_t iotjs_mqtt_subscribe_handler( + const jerry_value_t jthis, const jerry_value_t jargv[], + const jerry_value_t jargc, + const iotjs_mqtt_control_packet_type packet_type) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(2, any, number); + + DJS_CHECK(packet_type == SUBSCRIBE || packet_type == UNSUBSCRIBE); + + iotjs_tmp_buffer_t topic; + iotjs_jval_as_tmp_buffer(JS_GET_ARG(0, any), &topic); + + if (jerry_value_is_error(topic.jval)) { + return topic.jval; + } + + if (topic.buffer == NULL || topic.length >= UINT16_MAX) { + iotjs_free_tmp_buffer(&topic); + + return JS_CREATE_ERROR(COMMON, "Topic for SUBSCRIBE is empty or too long."); + } + + // header bits: |2 bit qos | 16 bit packet id | + // qos is only available in case of subscribe + uint32_t header = (uint32_t)JS_GET_ARG(1, number); + uint32_t packet_identifier = (header & 0xFFFF); + + // Low 4 bits must be 0,0,1,0 + uint8_t header_byte = (packet_type << 4) | (1 << 1); + + size_t payload_len = topic.length + IOTJS_MQTT_LSB_MSB_SIZE; + + if (packet_type == SUBSCRIBE) { + // Add place for the SUBSCRIBE QoS data. + payload_len += sizeof(uint8_t); + } + + size_t variable_header_len = IOTJS_MQTT_LSB_MSB_SIZE; + uint32_t remaining_length = payload_len + variable_header_len; + size_t full_len = sizeof(header_byte) + + get_remaining_length_size(remaining_length) + + 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++ = header_byte; + + buff_ptr = iotjs_encode_remaining_length(buff_ptr, remaining_length); + + // Packet id format is MSB / LSB. + *buff_ptr++ = (uint8_t)(packet_identifier >> 8); + *buff_ptr++ = (uint8_t)(packet_identifier & 0x00FF); + + buff_ptr = iotjs_mqtt_string_serialize(buff_ptr, &topic); + + if (packet_type == SUBSCRIBE) { + uint8_t qos = ((header >> 16) & 0x3); + buff_ptr[0] = qos; + } + + iotjs_free_tmp_buffer(&topic); + return jbuff; +} + + +JS_FUNCTION(mqtt_unsubscribe) { + return iotjs_mqtt_subscribe_handler(jthis, jargv, jargc, UNSUBSCRIBE); +} + + +JS_FUNCTION(mqtt_subscribe) { + return iotjs_mqtt_subscribe_handler(jthis, jargv, jargc, SUBSCRIBE); +} + + +JS_FUNCTION(mqtt_ping) { + 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(mqtt_disconnect) { + 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(mqtt_send_ack) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(2, number, number); + + uint8_t ack_type = (uint8_t)JS_GET_ARG(0, number); + uint16_t packet_id = (uint16_t)JS_GET_ARG(1, number); + + uint8_t header_byte = (ack_type << 4); + + if (ack_type == PUBREL) { + header_byte |= 0x2; + } + + 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(uint8_t) * 2 + 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] = 2; /* length */ + buff_ptr[2] = packet_identifier_msb; + buff_ptr[3] = packet_identifier_lsb; + + return jbuff; +} + +jerry_value_t iotjs_init_mqtt(void) { + jerry_value_t jmqtt = jerry_create_object(); + iotjs_jval_set_method(jmqtt, IOTJS_MAGIC_STRING_CONNECT, mqtt_connect); + iotjs_jval_set_method(jmqtt, IOTJS_MAGIC_STRING_DISCONNECT, mqtt_disconnect); + iotjs_jval_set_method(jmqtt, IOTJS_MAGIC_STRING_PING, mqtt_ping); + iotjs_jval_set_method(jmqtt, IOTJS_MAGIC_STRING_PUBLISH, mqtt_publish); + iotjs_jval_set_method(jmqtt, IOTJS_MAGIC_STRING_MQTTINIT, mqtt_init); + iotjs_jval_set_method(jmqtt, IOTJS_MAGIC_STRING_MQTTRECEIVE, mqtt_receive); + iotjs_jval_set_method(jmqtt, IOTJS_MAGIC_STRING_SENDACK, mqtt_send_ack); + iotjs_jval_set_method(jmqtt, IOTJS_MAGIC_STRING_SUBSCRIBE, mqtt_subscribe); + iotjs_jval_set_method(jmqtt, IOTJS_MAGIC_STRING_UNSUBSCRIBE, + mqtt_unsubscribe); + + return jmqtt; +} diff --git a/src/modules/iotjs_module_mqtt.h b/src/modules/iotjs_module_mqtt.h new file mode 100644 index 0000000000..22317b69b9 --- /dev/null +++ b/src/modules/iotjs_module_mqtt.h @@ -0,0 +1,139 @@ +/* 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. + */ +typedef 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; + +// Packet error types +typedef enum { + MQTT_ERR_UNACCEPTABLE_PROTOCOL = 1, + MQTT_ERR_BAD_IDENTIFIER = 2, + MQTT_ERR_SERVER_UNAVIABLE = 3, + MQTT_ERR_BAD_CREDENTIALS = 4, + MQTT_ERR_UNAUTHORISED = 5, + MQTT_ERR_CORRUPTED_PACKET = 6, + MQTT_ERR_UNALLOWED_PACKET = 7, + MQTT_ERR_SUBSCRIPTION_FAILED = 8, +} iotjs_mqtt_packet_error_t; + +/* + * 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; + +/* + * 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; +} mqtt_header_t; + +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; + +typedef struct { + char *buffer; + uint32_t buffer_length; +} iotjs_mqttclient_t; + +#endif /* IOTJS_MODULE_MQTT_H */ diff --git a/src/modules/iotjs_module_periph_common.c b/src/modules/iotjs_module_periph_common.c new file mode 100644 index 0000000000..90af5a2900 --- /dev/null +++ b/src/modules/iotjs_module_periph_common.c @@ -0,0 +1,207 @@ +/* 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_module_periph_common.h" +#include "iotjs_module_adc.h" +#include "iotjs_module_gpio.h" +#include "iotjs_module_i2c.h" +#include "iotjs_module_pwm.h" +#include "iotjs_module_spi.h" +#include "iotjs_module_uart.h" +#include "iotjs_uv_request.h" + +const char* iotjs_periph_error_str(uint8_t op) { + switch (op) { +#if ENABLE_MODULE_ADC + case kAdcOpClose: + return "Close error, cannot close ADC"; + case kAdcOpOpen: + return "Open error, cannot open ADC"; + case kAdcOpRead: + return "Read error, cannot read ADC"; +#endif /* ENABLE_MODULE_ADC */ +#if ENABLE_MODULE_GPIO + case kGpioOpOpen: + return "Open error, cannot open GPIO"; + case kGpioOpWrite: + return "Write error, cannot write GPIO"; + case kGpioOpRead: + return "Read error, cannot read GPIO"; + case kGpioOpClose: + return "Close error, cannot close GPIO"; +#endif /* ENABLE_MODULE_GPIO */ +#if ENABLE_MODULE_I2C + case kI2cOpOpen: + return "Open error, cannot open I2C"; + case kI2cOpWrite: + return "Write error, cannot write I2C"; + case kI2cOpRead: + return "Read error, cannot read I2C"; + case kI2cOpClose: + return "Close error, cannot close I2C"; +#endif /* ENABLE_MODULE_I2C */ +#if ENABLE_MODULE_PWM + case kPwmOpClose: + return "Cannot close PWM device"; + case kPwmOpOpen: + return "Failed to open PWM device"; + case kPwmOpSetDutyCycle: + return "Failed to set duty-cycle"; + case kPwmOpSetEnable: + return "Failed to set enable"; + case kPwmOpSetFrequency: + return "Failed to set frequency"; + case kPwmOpSetPeriod: + return "Failed to set period"; +#endif /* ENABLE_MODULE_PWM */ +#if ENABLE_MODULE_SPI + case kSpiOpClose: + return "Close error, cannot close SPI"; + case kSpiOpOpen: + return "Open error, cannot open SPI"; + case kSpiOpTransferArray: + case kSpiOpTransferBuffer: + return "Transfer error, cannot transfer from SPI device"; +#endif /* ENABLE_MODULE_SPI */ +#if ENABLE_MODULE_UART + case kUartOpClose: + return "Close error, failed to close UART device"; + case kUartOpOpen: + return "Open error, failed to open UART device"; + case kUartOpWrite: + return "Write error, cannot write to UART device"; +#endif /* ENABLE_MODULE_UART */ + default: + return "Unknown error"; + } +} + +static void after_worker(uv_work_t* work_req, int status) { + iotjs_periph_data_t* worker_data = + (iotjs_periph_data_t*)IOTJS_UV_REQUEST_EXTRA_DATA(work_req); + + size_t jargc = 0; + jerry_value_t jargs[2] = { 0 }; + + if (status) { + jargs[jargc++] = iotjs_jval_create_error_without_error_flag("System error"); + } else { + if (!worker_data->result) { + jargs[jargc++] = iotjs_jval_create_error_without_error_flag( + iotjs_periph_error_str(worker_data->op)); + } else { + jargs[jargc++] = jerry_create_null(); + switch (worker_data->op) { + case kAdcOpClose: + case kAdcOpOpen: + case kGpioOpClose: + case kGpioOpOpen: + case kGpioOpWrite: + case kI2cOpClose: + case kI2cOpOpen: + case kI2cOpWrite: + case kSpiOpClose: + case kSpiOpOpen: + case kPwmOpClose: + case kPwmOpOpen: + case kPwmOpSetDutyCycle: + case kPwmOpSetEnable: + case kPwmOpSetFrequency: + case kPwmOpSetPeriod: + case kUartOpClose: + case kUartOpOpen: + case kUartOpWrite: { + break; + } + case kAdcOpRead: { +#if ENABLE_MODULE_ADC + iotjs_adc_t* adc = (iotjs_adc_t*)worker_data->data; + jargs[jargc++] = jerry_create_number(adc->value); +#endif /* ENABLE_MODULE_ADC */ + break; + } + case kGpioOpRead: { +#if ENABLE_MODULE_GPIO + iotjs_gpio_t* gpio = (iotjs_gpio_t*)worker_data->data; + jargs[jargc++] = jerry_create_boolean(gpio->value); +#endif /* ENABLE_MODULE_GPIO */ + break; + } + case kI2cOpRead: { +#if ENABLE_MODULE_I2C + iotjs_i2c_t* i2c = (iotjs_i2c_t*)worker_data->data; + jargs[jargc++] = + iotjs_jval_create_byte_array(i2c->buf_len, i2c->buf_data); + IOTJS_RELEASE(i2c->buf_data); +#endif /* ENABLE_MODULE_I2C */ + break; + } + case kSpiOpTransferArray: + case kSpiOpTransferBuffer: { +#if ENABLE_MODULE_SPI + iotjs_spi_t* spi = (iotjs_spi_t*)worker_data->data; + // Append read data + jargs[jargc++] = + iotjs_jval_create_byte_array(spi->buf_len, spi->rx_buf_data); + IOTJS_RELEASE(spi->rx_buf_data); +#endif /* ENABLE_MODULE_SPI */ + break; + } + default: { + IOTJS_ASSERT(!"Unreachable"); + break; + } + } + } +#if ENABLE_MODULE_SPI + if (worker_data->op == kSpiOpTransferArray) { + iotjs_spi_t* spi = (iotjs_spi_t*)worker_data->data; + IOTJS_RELEASE(spi->tx_buf_data); + } +#endif /* ENABLE_MODULE_SPI */ +#if ENABLE_MODULE_UART + if (worker_data->op == kUartOpWrite) { + iotjs_uart_t* uart = (iotjs_uart_t*)worker_data->data; + iotjs_string_destroy(&uart->buf_data); + } +#endif /* ENABLE_MODULE_UART */ + } + + jerry_value_t jcallback = *IOTJS_UV_REQUEST_JSCALLBACK(work_req); + if (jerry_value_is_function(jcallback)) { + iotjs_invoke_callback(jcallback, jerry_create_undefined(), jargs, jargc); + } + + for (size_t i = 0; i < jargc; i++) { + jerry_release_value(jargs[i]); + } + + iotjs_uv_request_destroy((uv_req_t*)work_req); +} + + +void iotjs_periph_call_async(void* data, jerry_value_t jcallback, uint8_t op, + uv_work_cb worker) { + uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get()); + + uv_req_t* work_req = iotjs_uv_request_create(sizeof(uv_work_t), jcallback, + sizeof(iotjs_periph_data_t)); + iotjs_periph_data_t* worker_data = + (iotjs_periph_data_t*)IOTJS_UV_REQUEST_EXTRA_DATA(work_req); + worker_data->op = op; + worker_data->data = data; + + uv_queue_work(loop, (uv_work_t*)work_req, worker, after_worker); +} diff --git a/src/modules/iotjs_module_periph_common.h b/src/modules/iotjs_module_periph_common.h new file mode 100644 index 0000000000..ec29ac6466 --- /dev/null +++ b/src/modules/iotjs_module_periph_common.h @@ -0,0 +1,67 @@ +/* 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_PERIPH_COMMON_H +#define IOTJS_MODULE_PERIPH_COMMON_H + +#include "iotjs_def.h" + +typedef enum { + kAdcOpOpen, + kAdcOpRead, + kAdcOpClose, + kGpioOpOpen, + kGpioOpWrite, + kGpioOpRead, + kGpioOpClose, + kI2cOpOpen, + kI2cOpClose, + kI2cOpWrite, + kI2cOpRead, + kPwmOpClose, + kPwmOpOpen, + kPwmOpSetDutyCycle, + kPwmOpSetEnable, + kPwmOpSetFrequency, + kPwmOpSetPeriod, + kSpiOpClose, + kSpiOpOpen, + kSpiOpTransferArray, + kSpiOpTransferBuffer, + kUartOpClose, + kUartOpOpen, + kUartOpWrite +} iotjs_periph_op_t; + +typedef struct { + uint8_t op; + bool result; + void* data; +} iotjs_periph_data_t; + +const char* iotjs_periph_error_str(uint8_t op); +void iotjs_periph_call_async(void* type_p, jerry_value_t jcallback, uint8_t op, + uv_work_cb worker); + +#define IOTJS_DEFINE_PERIPH_CREATE_FUNCTION(name) \ + static iotjs_##name##_t* name##_create(const jerry_value_t jobject) { \ + iotjs_##name##_t* data = IOTJS_ALLOC(iotjs_##name##_t); \ + iotjs_##name##_create_platform_data(data); \ + data->jobject = jobject; \ + jerry_set_object_native_pointer(jobject, data, &this_module_native_info); \ + return data; \ + } + +#endif /* IOTJS_MODULE_PERIPH_COMMON_H */ diff --git a/src/modules/iotjs_module_process.c b/src/modules/iotjs_module_process.c index 1f658b9052..b12dbb132d 100644 --- a/src/modules/iotjs_module_process.c +++ b/src/modules/iotjs_module_process.c @@ -14,195 +14,260 @@ */ #include "iotjs_def.h" +#include "iotjs_compatibility.h" #include "iotjs_js.h" #include "jerryscript-debugger.h" - #include +#ifndef WIN32 +#include +#endif /* !WIN32 */ -JHANDLER_FUNCTION(Binding) { - JHANDLER_CHECK_ARGS(1, number); - - ModuleKind module_kind = (ModuleKind)JHANDLER_GET_ARG(0, number); - - const iotjs_jval_t* jmodule = - iotjs_module_initialize_if_necessary(module_kind); +static jerry_value_t wrap_eval(const char* name, size_t name_len, + const char* source, size_t length) { + static const char* args = "exports, require, module, native"; + jerry_value_t res = + jerry_parse_function((const jerry_char_t*)name, name_len, + (const jerry_char_t*)args, strlen(args), + (const jerry_char_t*)source, length, + JERRY_PARSE_NO_OPTS); - iotjs_jhandler_return_jval(jhandler, jmodule); + return res; } -static iotjs_jval_t WrapEval(const char* name, size_t name_len, - const char* source, size_t length, bool* throws) { - static const char* wrapper[2] = { "(function(exports, require, module) {", - "\n});\n" }; +JS_FUNCTION(proc_compile) { + DJS_CHECK_ARGS(2, string, string); - size_t len0 = strlen(wrapper[0]); - size_t len1 = strlen(wrapper[1]); + iotjs_string_t file = JS_GET_ARG(0, string); + iotjs_string_t source = JS_GET_ARG(1, string); - size_t buffer_length = len0 + len1 + length; - char* buffer = iotjs_buffer_allocate(buffer_length); - memcpy(buffer, wrapper[0], len0); - memcpy(buffer + len0, source, length); - memcpy(buffer + len0 + length, wrapper[1], len1); + const char* filename = iotjs_string_data(&file); + +#ifdef JERRY_DEBUGGER + const iotjs_environment_t* env = iotjs_environment_get(); + if (iotjs_environment_config(env)->debugger != NULL) { + jerry_debugger_stop(); + } +#endif - iotjs_jval_t res = iotjs_jhelper_eval(name, name_len, (uint8_t*)buffer, - buffer_length, false, throws); + jerry_value_t jres = + wrap_eval(filename, strlen(filename), iotjs_string_data(&source), + iotjs_string_size(&source)); - iotjs_buffer_release(buffer); + iotjs_string_destroy(&file); + iotjs_string_destroy(&source); - return res; + return jres; } -JHANDLER_FUNCTION(Compile) { - JHANDLER_CHECK_ARGS(2, string, string); +#ifdef JERRY_DEBUGGER +// Callback function for debugger_get_source +static jerry_value_t wait_for_source_callback( + const jerry_char_t* resource_name_p, size_t resource_name_size, + const jerry_char_t* source_p, size_t size, void* data) { + IOTJS_UNUSED(data); - iotjs_string_t file = JHANDLER_GET_ARG(0, string); - iotjs_string_t source = JHANDLER_GET_ARG(1, string); + jerry_value_t ret_val = jerry_create_array(2); + jerry_value_t jname = + jerry_create_string_sz(resource_name_p, resource_name_size); + jerry_value_t jsource = jerry_create_string_sz(source_p, size); + jerry_set_property_by_index(ret_val, 0, jname); + jerry_set_property_by_index(ret_val, 1, jsource); - const char* filename = iotjs_string_data(&file); - const iotjs_environment_t* env = iotjs_environment_get(); + jerry_release_value(jname); + jerry_release_value(jsource); - if (iotjs_environment_config(env)->debugger) { - jerry_debugger_stop(); - } + return ret_val; +} - bool throws; - iotjs_jval_t jres = - WrapEval(filename, strlen(filename), iotjs_string_data(&source), - iotjs_string_size(&source), &throws); - if (!throws) { - iotjs_jhandler_return_jval(jhandler, &jres); - } else { - iotjs_jhandler_throw(jhandler, &jres); - } +// Export JS module received from the debugger client +JS_FUNCTION(debugger_get_source) { + jerry_debugger_wait_for_source_status_t receive_status; + jerry_value_t ret_val = jerry_create_array(0); + uint8_t counter = 0; + do { + jerry_value_t res; + receive_status = + jerry_debugger_wait_for_client_source(wait_for_source_callback, NULL, + &res); + + if (receive_status == JERRY_DEBUGGER_SOURCE_RECEIVED) { + jerry_set_property_by_index(ret_val, counter++, res); + jerry_release_value(res); + } - iotjs_string_destroy(&file); - iotjs_string_destroy(&source); - iotjs_jval_destroy(&jres); + if (receive_status == JERRY_DEBUGGER_CONTEXT_RESET_RECEIVED) { + iotjs_environment_config(iotjs_environment_get()) + ->debugger->context_reset = true; + break; + } + } while (receive_status != JERRY_DEBUGGER_SOURCE_END); + + return ret_val; } +#endif -JHANDLER_FUNCTION(CompileNativePtr) { - JHANDLER_CHECK_ARGS(1, string); +JS_FUNCTION(proc_compile_module) { + DJS_CHECK_ARGS(2, object, function); - iotjs_string_t id = JHANDLER_GET_ARG(0, string); + jerry_value_t jmodule = JS_GET_ARG(0, object); + jerry_value_t jrequire = JS_GET_ARG(1, function); + + jerry_value_t jid = iotjs_jval_get_property(jmodule, "id"); + if (!jerry_value_is_string(jid)) { + return JS_CREATE_ERROR(COMMON, "Unknown native module"); + } + iotjs_string_t id = iotjs_jval_as_string(jid); + jerry_release_value(jid); const char* name = iotjs_string_data(&id); int i = 0; - while (natives[i].name != NULL) { - if (!strcmp(natives[i].name, name)) { + while (js_modules[i].name != NULL) { + if (!strcmp(js_modules[i].name, name)) { break; } i++; } - if (natives[i].name != NULL) { - bool throws; + jerry_value_t native_module_jval = iotjs_module_get(name); + + if (jerry_value_is_error(native_module_jval)) { + iotjs_string_destroy(&id); + return native_module_jval; + } + + jerry_value_t jres = jerry_create_undefined(); + + if (js_modules[i].name != NULL) { #ifdef ENABLE_SNAPSHOT - iotjs_jval_t jres = iotjs_jhelper_exec_snapshot(natives[i].code, - natives[i].length, &throws); + jres = jerry_exec_snapshot((const uint32_t*)iotjs_js_modules_s, + iotjs_js_modules_l, js_modules[i].idx, + JERRY_SNAPSHOT_EXEC_ALLOW_STATIC); #else - iotjs_jval_t jres = - WrapEval(name, iotjs_string_size(&id), (const char*)natives[i].code, - natives[i].length, &throws); + jres = wrap_eval(name, iotjs_string_size(&id), + (const char*)js_modules[i].code, js_modules[i].length); #endif - - if (!throws) { - iotjs_jhandler_return_jval(jhandler, &jres); - } else { - iotjs_jhandler_throw(jhandler, &jres); + if (!jerry_value_is_error(jres)) { + jerry_value_t jexports = iotjs_jval_get_property(jmodule, "exports"); + jerry_value_t args[] = { jexports, jrequire, jmodule, + native_module_jval }; + + jerry_value_t jfunc = jres; + jres = jerry_call_function(jfunc, jerry_create_undefined(), args, + sizeof(args) / sizeof(jerry_value_t)); + jerry_release_value(jfunc); + jerry_release_value(jexports); } - iotjs_jval_destroy(&jres); + } else if (!jerry_value_is_undefined(native_module_jval)) { + iotjs_jval_set_property_jval(jmodule, "exports", native_module_jval); } else { - iotjs_jval_t jerror = iotjs_jval_create_error("Unknown native module"); - iotjs_jhandler_throw(jhandler, &jerror); - iotjs_jval_destroy(&jerror); + jres = JS_CREATE_ERROR(COMMON, "Unknown native module"); } iotjs_string_destroy(&id); + + return jres; } -JHANDLER_FUNCTION(ReadSource) { - JHANDLER_CHECK_ARGS(1, string); +JS_FUNCTION(proc_read_source) { + DJS_CHECK_ARGS(1, string); + + iotjs_string_t path = JS_GET_ARG(0, string); + const iotjs_environment_t* env = iotjs_environment_get(); + int err; + uv_fs_t fs_req; + err = uv_fs_stat(iotjs_environment_loop(env), &fs_req, + iotjs_string_data(&path), NULL); + uv_fs_req_cleanup(&fs_req); + + if (err || !S_ISREG(fs_req.statbuf.st_mode)) { + iotjs_string_destroy(&path); + return JS_CREATE_ERROR(COMMON, "ReadSource error, not a regular file"); + } - iotjs_string_t path = JHANDLER_GET_ARG(0, string); iotjs_string_t code = iotjs_file_read(iotjs_string_data(&path)); - iotjs_jhandler_return_string(jhandler, &code); + jerry_value_t ret_val = iotjs_jval_create_string(&code); iotjs_string_destroy(&path); iotjs_string_destroy(&code); -} + return ret_val; +} -JHANDLER_FUNCTION(Cwd) { - JHANDLER_CHECK_ARGS(0); +JS_FUNCTION(proc_cwd) { char path[IOTJS_MAX_PATH_SIZE]; size_t size_path = sizeof(path); int err = uv_cwd(path, &size_path); if (err) { - JHANDLER_THROW(COMMON, "cwd error"); - return; + return JS_CREATE_ERROR(COMMON, "cwd error"); } - iotjs_jhandler_return_string_raw(jhandler, path); + + return jerry_create_string_from_utf8((const jerry_char_t*)path); } -JHANDLER_FUNCTION(Chdir) { - JHANDLER_CHECK_ARGS(1, string); - iotjs_string_t path = JHANDLER_GET_ARG(0, string); +JS_FUNCTION(proc_chdir) { + DJS_CHECK_ARGS(1, string); + + iotjs_string_t path = JS_GET_ARG(0, string); int err = uv_chdir(iotjs_string_data(&path)); if (err) { iotjs_string_destroy(&path); - JHANDLER_THROW(COMMON, "chdir error"); - return; + return JS_CREATE_ERROR(COMMON, "chdir error"); } iotjs_string_destroy(&path); + return jerry_create_undefined(); } -JHANDLER_FUNCTION(DoExit) { - JHANDLER_CHECK_ARGS(1, number); +#ifdef EXPOSE_GC +JS_FUNCTION(garbage_collector) { + jerry_gc(JERRY_GC_PRESSURE_LOW); - // Release builtin modules. - iotjs_module_list_cleanup(); + return jerry_create_undefined(); +} +#endif - // Release commonly used jerry values. - iotjs_binding_finalize(); - int exit_code = JHANDLER_GET_ARG(0, number); - exit(exit_code); -} +JS_FUNCTION(proc_do_exit) { + iotjs_environment_t* env = iotjs_environment_get(); + if (!iotjs_environment_is_exiting(env)) { + DJS_CHECK_ARGS(1, number); + int exit_code = JS_GET_ARG(0, number); -void SetNativeSources(iotjs_jval_t* native_sources) { - for (int i = 0; natives[i].name; i++) { - iotjs_jval_set_property_jval(native_sources, natives[i].name, - iotjs_jval_get_boolean(true)); + iotjs_set_process_exitcode(exit_code); + iotjs_environment_set_state(env, kExiting); } + return jerry_create_undefined(); } -static void SetProcessEnv(iotjs_jval_t* process) { - const char *homedir, *iotjspath, *iotjsenv; +static void set_process_env(jerry_value_t process) { + const char *homedir, *iotjspath, *iotjsenv, *extra_module_path, + *working_dir_path; - homedir = getenv("HOME"); + homedir = getenv(IOTJS_MAGIC_STRING_HOME_U); if (homedir == NULL) { homedir = ""; } - iotjspath = getenv("IOTJS_PATH"); + iotjspath = getenv(IOTJS_MAGIC_STRING_IOTJS_PATH_U); if (iotjspath == NULL) { -#if defined(__NUTTX__) || defined(__TIZENRT__) +#if defined(__NUTTX__) iotjspath = "/mnt/sdcard"; +#elif defined(__TIZENRT__) + iotjspath = "/rom"; #else iotjspath = ""; #endif @@ -214,93 +279,168 @@ static void SetProcessEnv(iotjs_jval_t* process) { iotjsenv = ""; #endif - iotjs_jval_t env = iotjs_jval_create_object(); - iotjs_jval_set_property_string_raw(&env, IOTJS_MAGIC_STRING_HOME, homedir); - iotjs_jval_set_property_string_raw(&env, IOTJS_MAGIC_STRING_IOTJS_PATH, + 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); + iotjs_jval_set_property_string_raw(env, IOTJS_MAGIC_STRING_IOTJS_PATH_U, iotjspath); - iotjs_jval_set_property_string_raw(&env, IOTJS_MAGIC_STRING_IOTJS_ENV, + iotjs_jval_set_property_string_raw(env, IOTJS_MAGIC_STRING_IOTJS_ENV_U, iotjsenv); + 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); + iotjs_jval_set_property_jval(process, IOTJS_MAGIC_STRING_ENV, env); - iotjs_jval_destroy(&env); + jerry_release_value(env); } -static void SetProcessIotjs(iotjs_jval_t* process) { +static void set_process_iotjs(jerry_value_t process) { // IoT.js specific - iotjs_jval_t iotjs = iotjs_jval_create_object(); - iotjs_jval_set_property_jval(process, IOTJS_MAGIC_STRING_IOTJS, &iotjs); + jerry_value_t iotjs = jerry_create_object(); + iotjs_jval_set_property_jval(process, IOTJS_MAGIC_STRING_IOTJS, iotjs); - iotjs_jval_set_property_string_raw(&iotjs, IOTJS_MAGIC_STRING_BOARD, + iotjs_jval_set_property_string_raw(iotjs, IOTJS_MAGIC_STRING_BOARD, TOSTRING(TARGET_BOARD)); - iotjs_jval_destroy(&iotjs); + jerry_release_value(iotjs); } -static void SetProcessArgv(iotjs_jval_t* process) { +static void set_process_argv(jerry_value_t process) { const iotjs_environment_t* env = iotjs_environment_get(); uint32_t argc = iotjs_environment_argc(env); - iotjs_jval_t argv = iotjs_jval_create_array(argc); + jerry_value_t argv = jerry_create_array(argc); for (uint32_t i = 0; i < argc; ++i) { const char* argvi = iotjs_environment_argv(env, i); - iotjs_jval_t arg = iotjs_jval_create_string_raw(argvi); - iotjs_jval_set_property_by_index(&argv, i, &arg); - iotjs_jval_destroy(&arg); + jerry_value_t arg = jerry_create_string((const jerry_char_t*)argvi); + iotjs_jval_set_property_by_index(argv, i, arg); + jerry_release_value(arg); } - iotjs_jval_set_property_jval(process, IOTJS_MAGIC_STRING_ARGV, &argv); + iotjs_jval_set_property_jval(process, IOTJS_MAGIC_STRING_ARGV, argv); - iotjs_jval_destroy(&argv); + jerry_release_value(argv); } -iotjs_jval_t InitProcess() { - iotjs_jval_t process = iotjs_jval_create_object(); +static void set_builtin_modules(jerry_value_t builtin_modules) { + for (unsigned i = 0; js_modules[i].name; i++) { + iotjs_jval_set_property_jval(builtin_modules, js_modules[i].name, + jerry_create_boolean(true)); + } + for (unsigned i = 0; i < iotjs_module_count; i++) { + iotjs_jval_set_property_jval(builtin_modules, iotjs_module_ro_data[i].name, + jerry_create_boolean(true)); + } +} + +static void set_process_private(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, proc_compile); + iotjs_jval_set_method(private, IOTJS_MAGIC_STRING_COMPILEMODULE, + proc_compile_module); + iotjs_jval_set_method(private, IOTJS_MAGIC_STRING_READSOURCE, + proc_read_source); + +#ifdef JERRY_DEBUGGER + // debugger + iotjs_jval_set_method(private, IOTJS_MAGIC_STRING_DEBUGGERGETSOURCE, + debugger_get_source); - iotjs_jval_set_method(&process, IOTJS_MAGIC_STRING_BINDING, Binding); - iotjs_jval_set_method(&process, IOTJS_MAGIC_STRING_COMPILE, Compile); - iotjs_jval_set_method(&process, IOTJS_MAGIC_STRING_COMPILENATIVEPTR, - CompileNativePtr); - 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_DOEXIT, DoExit); - SetProcessEnv(&process); + jerry_value_t wait_source_val = jerry_create_boolean(wait_source); + iotjs_jval_set_property_jval(private, IOTJS_MAGIC_STRING_DEBUGGERWAITSOURCE, + wait_source_val); - // process.native_sources - iotjs_jval_t native_sources = iotjs_jval_create_object(); - SetNativeSources(&native_sources); - iotjs_jval_set_property_jval(&process, IOTJS_MAGIC_STRING_NATIVE_SOURCES, - &native_sources); - iotjs_jval_destroy(&native_sources); + jerry_release_value(wait_source_val); +#endif + + jerry_release_value(private); +} + + +jerry_value_t iotjs_init_process(void) { + jerry_value_t process = jerry_create_object(); + + iotjs_jval_set_method(process, IOTJS_MAGIC_STRING_CWD, proc_cwd); + iotjs_jval_set_method(process, IOTJS_MAGIC_STRING_CHDIR, proc_chdir); + iotjs_jval_set_method(process, IOTJS_MAGIC_STRING_DOEXIT, proc_do_exit); +#ifdef EXPOSE_GC + iotjs_jval_set_method(process, IOTJS_MAGIC_STRING_GC, garbage_collector); +#endif +#ifdef DEBUG + jerry_property_descriptor_t prop_desc; + jerry_init_property_descriptor_fields(&prop_desc); + + prop_desc.is_value_defined = true; + prop_desc.is_writable_defined = true; + prop_desc.is_configurable_defined = true; + prop_desc.value = jerry_create_boolean(true); + + jerry_value_t property_name = + jerry_create_string((jerry_char_t*)IOTJS_MAGIC_STRING_DEBUG); + jerry_value_t prop_ret_val = + jerry_define_own_property(process, property_name, &prop_desc); + jerry_release_value(prop_ret_val); + jerry_release_value(property_name); + jerry_free_property_descriptor_fields(&prop_desc); +#endif +/* FIXME: Move this platform dependent code path to libtuv + * + * See the related commit in libuv: + * d708df110a03332224bd9be1bbd23093d9cf9022 + */ +#ifdef WIN32 + iotjs_jval_set_property_jval(process, IOTJS_MAGIC_STRING_PID, + jerry_create_number(GetCurrentProcessId())); +#else /* !WIN32 */ + iotjs_jval_set_property_jval(process, IOTJS_MAGIC_STRING_PID, + jerry_create_number(getpid())); +#endif /* WIN32 */ + set_process_env(process); + + // process.builtin_modules + jerry_value_t builtin_modules = jerry_create_object(); + set_builtin_modules(builtin_modules); + iotjs_jval_set_property_jval(process, IOTJS_MAGIC_STRING_BUILTIN_MODULES, + builtin_modules); + jerry_release_value(builtin_modules); // process.platform - iotjs_jval_set_property_string_raw(&process, IOTJS_MAGIC_STRING_PLATFORM, + iotjs_jval_set_property_string_raw(process, IOTJS_MAGIC_STRING_PLATFORM, TARGET_OS); // process.arch - iotjs_jval_set_property_string_raw(&process, IOTJS_MAGIC_STRING_ARCH, + iotjs_jval_set_property_string_raw(process, IOTJS_MAGIC_STRING_ARCH, TARGET_ARCH); - // Set iotjs - SetProcessIotjs(&process); - - SetProcessArgv(&process); - - // Binding module id. - iotjs_jval_t jbinding = - iotjs_jval_get_property(&process, IOTJS_MAGIC_STRING_BINDING); - -#define ENUMDEF_MODULE_LIST(upper, Camel, lower) \ - iotjs_jval_set_property_number(&jbinding, #lower, MODULE_##upper); + // process.version + iotjs_jval_set_property_string_raw(process, IOTJS_MAGIC_STRING_VERSION, + IOTJS_VERSION); - MAP_MODULE_LIST(ENUMDEF_MODULE_LIST) + // Set iotjs + set_process_iotjs(process); + bool wait_source = false; +#ifdef JERRY_DEBUGGER + if (iotjs_environment_config(iotjs_environment_get())->debugger != NULL) { + wait_source = iotjs_environment_config(iotjs_environment_get()) + ->debugger->wait_source; + } +#endif -#undef ENUMDEF_MODULE_LIST + if (!wait_source) { + set_process_argv(process); + } - iotjs_jval_destroy(&jbinding); + set_process_private(process, wait_source); return process; } diff --git a/src/modules/iotjs_module_pwm.c b/src/modules/iotjs_module_pwm.c index 7ef6f8acea..68e88015b8 100644 --- a/src/modules/iotjs_module_pwm.c +++ b/src/modules/iotjs_module_pwm.c @@ -13,364 +13,276 @@ * limitations under the License. */ + #include "iotjs_def.h" #include "iotjs_module_pwm.h" -#include "iotjs_objectwrap.h" +#include "iotjs_uv_request.h" -static iotjs_pwm_t* iotjs_pwm_instance_from_jval(const iotjs_jval_t* jpwm); IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(pwm); - -static iotjs_pwm_t* iotjs_pwm_create(const iotjs_jval_t* jpwm) { - iotjs_pwm_t* pwm = IOTJS_ALLOC(iotjs_pwm_t); - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_pwm_t, pwm); - iotjs_jobjectwrap_initialize(&_this->jobjectwrap, jpwm, - &this_module_native_info); - - _this->period = -1; - _this->duty_cycle = 0; -#if defined(__NUTTX__) - _this->device_fd = -1; -#endif - return pwm; -} - +IOTJS_DEFINE_PERIPH_CREATE_FUNCTION(pwm); static void iotjs_pwm_destroy(iotjs_pwm_t* pwm) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_pwm_t, pwm); - iotjs_jobjectwrap_destroy(&_this->jobjectwrap); -#if defined(__linux__) - iotjs_string_destroy(&_this->device); -#endif + iotjs_pwm_destroy_platform_data(pwm->platform_data); IOTJS_RELEASE(pwm); } - -#define THIS iotjs_pwm_reqwrap_t* pwm_reqwrap - - -static iotjs_pwm_reqwrap_t* iotjs_pwm_reqwrap_create( - const iotjs_jval_t* jcallback, iotjs_pwm_t* pwm, PwmOp op) { - iotjs_pwm_reqwrap_t* pwm_reqwrap = IOTJS_ALLOC(iotjs_pwm_reqwrap_t); - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_pwm_reqwrap_t, pwm_reqwrap); - - iotjs_reqwrap_initialize(&_this->reqwrap, jcallback, (uv_req_t*)&_this->req); - - _this->req_data.op = op; - _this->pwm_instance = pwm; - _this->req_data.caller = NULL; - - return pwm_reqwrap; -} - - -static void iotjs_pwm_reqwrap_destroy(THIS) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_pwm_reqwrap_t, pwm_reqwrap); - iotjs_reqwrap_destroy(&_this->reqwrap); - IOTJS_RELEASE(pwm_reqwrap); -} - - -static void iotjs_pwm_reqwrap_dispatched(THIS) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_pwm_reqwrap_t, pwm_reqwrap); - iotjs_pwm_reqwrap_destroy(pwm_reqwrap); +static void pwm_worker(uv_work_t* work_req) { + iotjs_periph_data_t* worker_data = + (iotjs_periph_data_t*)IOTJS_UV_REQUEST_EXTRA_DATA(work_req); + iotjs_pwm_t* pwm = (iotjs_pwm_t*)worker_data->data; + + switch (worker_data->op) { + case kPwmOpClose: + worker_data->result = iotjs_pwm_close(pwm); + break; + case kPwmOpOpen: + worker_data->result = iotjs_pwm_open(pwm); + break; + case kPwmOpSetDutyCycle: + worker_data->result = iotjs_pwm_set_dutycycle(pwm); + break; + case kPwmOpSetEnable: + worker_data->result = iotjs_pwm_set_enable(pwm); + break; + case kPwmOpSetFrequency: /* update the period */ + case kPwmOpSetPeriod: + worker_data->result = iotjs_pwm_set_period(pwm); + break; + default: + IOTJS_ASSERT(!"Invalid Operation"); + } } +static jerry_value_t pwm_set_configuration(iotjs_pwm_t* pwm, + jerry_value_t jconfig) { + JS_GET_REQUIRED_CONF_VALUE(jconfig, pwm->duty_cycle, + IOTJS_MAGIC_STRING_DUTYCYCLE, number); + if (pwm->duty_cycle < 0.0 || pwm->duty_cycle > 1.0) { + return JS_CREATE_ERROR(RANGE, "pwm.dutyCycle must be within 0.0 and 1.0"); + } -static uv_work_t* iotjs_pwm_reqwrap_req(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_reqwrap_t, pwm_reqwrap); - return &_this->req; -} + JS_GET_REQUIRED_CONF_VALUE(jconfig, pwm->period, IOTJS_MAGIC_STRING_PERIOD, + number); + if (pwm->period < 0) { + return JS_CREATE_ERROR(RANGE, "pwm.period must be a positive value"); + } + JS_GET_REQUIRED_CONF_VALUE(jconfig, pwm->pin, IOTJS_MAGIC_STRING_PIN, number); -static const iotjs_jval_t* iotjs_pwm_reqwrap_jcallback(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_reqwrap_t, pwm_reqwrap); - return iotjs_reqwrap_jcallback(&_this->reqwrap); + return jerry_create_undefined(); } +JS_FUNCTION(pwm_constructor) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(1, object); + DJS_CHECK_ARG_IF_EXIST(1, function); -static iotjs_pwm_t* iotjs_pwm_instance_from_jval(const iotjs_jval_t* jpwm) { - uintptr_t handle = iotjs_jval_get_object_native_handle(jpwm); - return (iotjs_pwm_t*)handle; -} + // Create PWM object + jerry_value_t jpwm = JS_GET_THIS(); + iotjs_pwm_t* pwm = pwm_create(jpwm); + jerry_value_t jconfig; + JS_GET_REQUIRED_ARG_VALUE(0, jconfig, IOTJS_MAGIC_STRING_CONFIG, object); -iotjs_pwm_reqwrap_t* iotjs_pwm_reqwrap_from_request(uv_work_t* req) { - return (iotjs_pwm_reqwrap_t*)(iotjs_reqwrap_from_request((uv_req_t*)req)); -} + jerry_value_t res = iotjs_pwm_set_platform_config(pwm, jconfig); + if (jerry_value_is_error(res)) { + return res; + } + IOTJS_ASSERT(jerry_value_is_undefined(res)); + res = pwm_set_configuration(pwm, jconfig); + if (jerry_value_is_error(res)) { + return res; + } + IOTJS_ASSERT(jerry_value_is_undefined(res)); -iotjs_pwm_reqdata_t* iotjs_pwm_reqwrap_data(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_reqwrap_t, pwm_reqwrap); - return &_this->req_data; -} + jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(1, function); + // If the callback doesn't exist, it is completed synchronously. + // Otherwise, it will be executed asynchronously. + if (!jerry_value_is_null(jcallback)) { + iotjs_periph_call_async(pwm, jcallback, kPwmOpOpen, pwm_worker); + } else if (!iotjs_pwm_open(pwm)) { + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kPwmOpOpen)); + } -iotjs_pwm_t* iotjs_pwm_instance_from_reqwrap(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_reqwrap_t, pwm_reqwrap); - return _this->pwm_instance; + return jerry_create_undefined(); } +JS_FUNCTION(pwm_close) { + JS_DECLARE_THIS_PTR(pwm, pwm); + DJS_CHECK_ARG_IF_EXIST(1, function); -static void iotjs_pwm_set_configuration(const iotjs_jval_t* jconfiguration, - iotjs_pwm_t* pwm) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_t, pwm); - - iotjs_jval_t jpin = - iotjs_jval_get_property(jconfiguration, IOTJS_MAGIC_STRING_PIN); - _this->pin = iotjs_jval_as_number(&jpin); - -#if defined(__linux__) - iotjs_jval_t jchip = - iotjs_jval_get_property(jconfiguration, IOTJS_MAGIC_STRING_CHIP); - _this->chip = iotjs_jval_as_number(&jchip); - iotjs_jval_destroy(&jchip); -#endif - - iotjs_jval_t jperiod = - iotjs_jval_get_property(jconfiguration, IOTJS_MAGIC_STRING_PERIOD); - if (iotjs_jval_is_number(&jperiod)) - _this->period = iotjs_jval_as_number(&jperiod); + iotjs_periph_call_async(pwm, JS_GET_ARG_IF_EXIST(0, function), kPwmOpClose, + pwm_worker); - iotjs_jval_t jduty_cycle = - iotjs_jval_get_property(jconfiguration, IOTJS_MAGIC_STRING_DUTYCYCLE); - if (iotjs_jval_is_number(&jduty_cycle)) - _this->duty_cycle = iotjs_jval_as_number(&jduty_cycle); - - iotjs_jval_destroy(&jpin); - iotjs_jval_destroy(&jperiod); - iotjs_jval_destroy(&jduty_cycle); + return jerry_create_undefined(); } -#undef THIS - - -static void iotjs_pwm_common_worker(uv_work_t* work_req) { - PWM_WORKER_INIT; - - IOTJS_ASSERT(req_data->caller != NULL); +JS_FUNCTION(pwm_close_sync) { + JS_DECLARE_THIS_PTR(pwm, pwm); - if (!req_data->caller(pwm)) { - req_data->result = false; - return; + if (!iotjs_pwm_close(pwm)) { + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kPwmOpClose)); } - req_data->result = true; + return jerry_create_undefined(); } +JS_FUNCTION(pwm_set_duty_cycle) { + JS_DECLARE_THIS_PTR(pwm, pwm); + DJS_CHECK_ARGS(1, number); + DJS_CHECK_ARG_IF_EXIST(1, function); -static void iotjs_pwm_after_worker(uv_work_t* work_req, int status) { - iotjs_pwm_reqwrap_t* req_wrap = iotjs_pwm_reqwrap_from_request(work_req); - iotjs_pwm_reqdata_t* req_data = iotjs_pwm_reqwrap_data(req_wrap); - iotjs_jargs_t jargs = iotjs_jargs_create(1); - bool result = req_data->result; + jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(1, function); - if (status) { - iotjs_jval_t error = iotjs_jval_create_error("System error"); - iotjs_jargs_append_jval(&jargs, &error); - iotjs_jval_destroy(&error); - } else { - switch (req_data->op) { - case kPwmOpOpen: - if (!result) { - iotjs_jargs_append_error(&jargs, "Failed to open PWM device"); - } else { - iotjs_jargs_append_null(&jargs); - } - break; - case kPwmOpSetDutyCycle: - if (!result) { - iotjs_jargs_append_error(&jargs, "Failed to set duty-cycle"); - } else { - iotjs_jargs_append_null(&jargs); - } - break; - case kPwmOpSetPeriod: - if (!result) { - iotjs_jargs_append_error(&jargs, "Failed to set period"); - } else { - iotjs_jargs_append_null(&jargs); - } - break; - case kPwmOpSetEnable: - if (!result) { - iotjs_jargs_append_error(&jargs, "Failed to set enable"); - } else { - iotjs_jargs_append_null(&jargs); - } - break; - case kPwmOpClose: - if (!result) { - iotjs_jargs_append_error(&jargs, "Cannot close PWM device"); - } else { - iotjs_jargs_append_null(&jargs); - } - break; - default: { - IOTJS_ASSERT(!"Unreachable"); - break; - } - } + pwm->duty_cycle = JS_GET_ARG(0, number); + if (pwm->duty_cycle < 0.0 || pwm->duty_cycle > 1.0) { + return JS_CREATE_ERROR(RANGE, "pwm.dutyCycle must be within 0.0 and 1.0"); } - const iotjs_jval_t* jcallback = iotjs_pwm_reqwrap_jcallback(req_wrap); - iotjs_make_callback(jcallback, iotjs_jval_get_undefined(), &jargs); - - iotjs_jargs_destroy(&jargs); + iotjs_periph_call_async(pwm, jcallback, kPwmOpSetDutyCycle, pwm_worker); - iotjs_pwm_reqwrap_dispatched(req_wrap); + return jerry_create_undefined(); } +JS_FUNCTION(pwm_set_duty_cycle_sync) { + JS_DECLARE_THIS_PTR(pwm, pwm); + DJS_CHECK_ARGS(1, number); -#define PWM_ASYNC(call, this, jcallback, op) \ - do { \ - uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get()); \ - iotjs_pwm_reqwrap_t* req_wrap = \ - iotjs_pwm_reqwrap_create(jcallback, this, op); \ - uv_work_t* req = iotjs_pwm_reqwrap_req(req_wrap); \ - uv_queue_work(loop, req, iotjs_pwm_##call##_worker, \ - iotjs_pwm_after_worker); \ - } while (0) - + pwm->duty_cycle = JS_GET_ARG(0, number); + if (pwm->duty_cycle < 0.0 || pwm->duty_cycle > 1.0) { + return JS_CREATE_ERROR(RANGE, "pwm.dutyCycle must be within 0.0 and 1.0"); + } -#define PWM_ASYNC_COMMON_WORKER(call, this, jcallback, op) \ - do { \ - uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get()); \ - iotjs_pwm_reqwrap_t* req_wrap = \ - iotjs_pwm_reqwrap_create(jcallback, this, op); \ - uv_work_t* req = iotjs_pwm_reqwrap_req(req_wrap); \ - iotjs_pwm_reqdata_t* req_data = iotjs_pwm_reqwrap_data(req_wrap); \ - req_data->caller = call; \ - uv_queue_work(loop, req, iotjs_pwm_common_worker, iotjs_pwm_after_worker); \ - } while (0) + if (!iotjs_pwm_set_dutycycle(pwm)) { + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kPwmOpSetDutyCycle)); + } + return jerry_create_undefined(); +} -JHANDLER_FUNCTION(PWMConstructor) { - DJHANDLER_CHECK_THIS(object); - DJHANDLER_CHECK_ARGS(2, object, function); +JS_FUNCTION(pwm_set_enable) { + JS_DECLARE_THIS_PTR(pwm, pwm); + DJS_CHECK_ARGS(1, boolean); + DJS_CHECK_ARG_IF_EXIST(1, function); - // Create PWM object - const iotjs_jval_t* jpwm = JHANDLER_GET_THIS(object); - iotjs_pwm_t* pwm = iotjs_pwm_create(jpwm); - IOTJS_ASSERT(pwm == iotjs_pwm_instance_from_jval(jpwm)); + jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(1, function); - const iotjs_jval_t* jconfiguration = JHANDLER_GET_ARG(0, object); - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG(1, function); + pwm->enable = JS_GET_ARG(0, boolean); - // Set configuration - iotjs_pwm_set_configuration(jconfiguration, pwm); + iotjs_periph_call_async(pwm, jcallback, kPwmOpSetEnable, pwm_worker); - PWM_ASYNC(open, pwm, jcallback, kPwmOpOpen); + return jerry_create_undefined(); } +JS_FUNCTION(pwm_set_enable_sync) { + JS_DECLARE_THIS_PTR(pwm, pwm); + DJS_CHECK_ARGS(1, boolean); -JHANDLER_FUNCTION(SetPeriod) { - JHANDLER_DECLARE_THIS_PTR(pwm, pwm); - - DJHANDLER_CHECK_ARGS(1, number); - DJHANDLER_CHECK_ARG_IF_EXIST(1, function); + pwm->enable = JS_GET_ARG(0, boolean); - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(1, function); - - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_t, pwm); - _this->period = JHANDLER_GET_ARG(0, number); - - if (jcallback) { - PWM_ASYNC_COMMON_WORKER(iotjs_pwm_set_period, pwm, jcallback, - kPwmOpSetPeriod); - } else { - if (!iotjs_pwm_set_period(pwm)) { - JHANDLER_THROW(COMMON, "PWM SetPeriod Error"); - } + if (!iotjs_pwm_set_enable(pwm)) { + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kPwmOpSetEnable)); } - iotjs_jhandler_return_null(jhandler); + return jerry_create_undefined(); } +static jerry_value_t pwm_set_period_or_frequency(iotjs_pwm_t* pwm, + const jerry_value_t jargv[], + const jerry_length_t jargc, + uint8_t op, bool async) { + const double num_value = JS_GET_ARG(0, number); -JHANDLER_FUNCTION(SetDutyCycle) { - JHANDLER_DECLARE_THIS_PTR(pwm, pwm); - - DJHANDLER_CHECK_ARGS(1, number); - DJHANDLER_CHECK_ARG_IF_EXIST(1, function); - - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(1, function); - - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_t, pwm); - _this->duty_cycle = JHANDLER_GET_ARG(0, number); + if (op == kPwmOpSetFrequency) { + if (num_value <= 0) { + return JS_CREATE_ERROR(RANGE, "frequency must be greater than 0"); + } + pwm->period = 1.0 / num_value; - if (jcallback) { - PWM_ASYNC_COMMON_WORKER(iotjs_pwm_set_dutycycle, pwm, jcallback, - kPwmOpSetDutyCycle); } else { - if (!iotjs_pwm_set_dutycycle(pwm)) { - JHANDLER_THROW(COMMON, "PWM SetDutyCycle Error"); + if (num_value < 0) { + return JS_CREATE_ERROR(RANGE, "period must be a positive value"); } + pwm->period = num_value; } - iotjs_jhandler_return_null(jhandler); -} - - -JHANDLER_FUNCTION(SetEnable) { - JHANDLER_DECLARE_THIS_PTR(pwm, pwm); - - DJHANDLER_CHECK_ARGS(1, boolean); - DJHANDLER_CHECK_ARG_IF_EXIST(1, function); - - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(1, function); - - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_t, pwm); - _this->enable = JHANDLER_GET_ARG(0, boolean); - - if (jcallback) { - PWM_ASYNC_COMMON_WORKER(iotjs_pwm_set_enable, pwm, jcallback, - kPwmOpSetEnable); + if (async) { + iotjs_periph_call_async(pwm, JS_GET_ARG_IF_EXIST(1, function), op, + pwm_worker); } else { - if (!iotjs_pwm_set_enable(pwm)) { - JHANDLER_THROW(COMMON, "PWM SetEnabe Error"); + if (!iotjs_pwm_set_period(pwm)) { + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(op)); } } - iotjs_jhandler_return_null(jhandler); + return jerry_create_undefined(); } +JS_FUNCTION(pwm_set_frequency) { + JS_DECLARE_THIS_PTR(pwm, pwm); + DJS_CHECK_ARGS(1, number); + DJS_CHECK_ARG_IF_EXIST(1, function); -JHANDLER_FUNCTION(Close) { - JHANDLER_DECLARE_THIS_PTR(pwm, pwm); - DJHANDLER_CHECK_ARG_IF_EXIST(0, function); - - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(0, function); - - if (jcallback) { - PWM_ASYNC_COMMON_WORKER(iotjs_pwm_close, pwm, jcallback, kPwmOpClose); - } else { - if (!iotjs_pwm_close(pwm)) { - JHANDLER_THROW(COMMON, "PWM Close Error"); - } - } - - iotjs_jhandler_return_null(jhandler); + return pwm_set_period_or_frequency(pwm, jargv, jargc, kPwmOpSetFrequency, + true); } +JS_FUNCTION(pwm_set_frequency_sync) { + JS_DECLARE_THIS_PTR(pwm, pwm); + DJS_CHECK_ARGS(1, number); -iotjs_jval_t InitPwm() { - iotjs_jval_t jpwm_constructor = - iotjs_jval_create_function_with_dispatch(PWMConstructor); + return pwm_set_period_or_frequency(pwm, jargv, jargc, kPwmOpSetFrequency, + false); +} - iotjs_jval_t jprototype = iotjs_jval_create_object(); +JS_FUNCTION(pwm_set_period) { + JS_DECLARE_THIS_PTR(pwm, pwm); + DJS_CHECK_ARGS(1, number); + DJS_CHECK_ARG_IF_EXIST(1, function); - iotjs_jval_set_method(&jprototype, IOTJS_MAGIC_STRING_SETPERIOD, SetPeriod); - iotjs_jval_set_method(&jprototype, IOTJS_MAGIC_STRING_SETDUTYCYCLE, - SetDutyCycle); - iotjs_jval_set_method(&jprototype, IOTJS_MAGIC_STRING_SETENABLE, SetEnable); - iotjs_jval_set_method(&jprototype, IOTJS_MAGIC_STRING_CLOSE, Close); + return pwm_set_period_or_frequency(pwm, jargv, jargc, kPwmOpSetPeriod, true); +} - iotjs_jval_set_property_jval(&jpwm_constructor, IOTJS_MAGIC_STRING_PROTOTYPE, - &jprototype); +JS_FUNCTION(pwm_set_period_sync) { + JS_DECLARE_THIS_PTR(pwm, pwm); + DJS_CHECK_ARGS(1, number); - iotjs_jval_destroy(&jprototype); + return pwm_set_period_or_frequency(pwm, jargv, jargc, kPwmOpSetPeriod, false); +} - return jpwm_constructor; +jerry_value_t iotjs_init_pwm(void) { + jerry_value_t jpwm_cons = jerry_create_external_function(pwm_constructor); + + jerry_value_t jprototype = jerry_create_object(); + + iotjs_jval_set_method(jprototype, IOTJS_MAGIC_STRING_CLOSE, pwm_close); + iotjs_jval_set_method(jprototype, IOTJS_MAGIC_STRING_CLOSESYNC, + pwm_close_sync); + iotjs_jval_set_method(jprototype, IOTJS_MAGIC_STRING_SETDUTYCYCLE, + pwm_set_duty_cycle); + iotjs_jval_set_method(jprototype, IOTJS_MAGIC_STRING_SETDUTYCYCLESYNC, + pwm_set_duty_cycle_sync); + iotjs_jval_set_method(jprototype, IOTJS_MAGIC_STRING_SETENABLE, + pwm_set_enable); + iotjs_jval_set_method(jprototype, IOTJS_MAGIC_STRING_SETENABLESYNC, + pwm_set_enable_sync); + iotjs_jval_set_method(jprototype, IOTJS_MAGIC_STRING_SETFREQUENCY, + pwm_set_frequency); + iotjs_jval_set_method(jprototype, IOTJS_MAGIC_STRING_SETFREQUENCYSYNC, + pwm_set_frequency_sync); + iotjs_jval_set_method(jprototype, IOTJS_MAGIC_STRING_SETPERIOD, + pwm_set_period); + iotjs_jval_set_method(jprototype, IOTJS_MAGIC_STRING_SETPERIODSYNC, + pwm_set_period_sync); + + iotjs_jval_set_property_jval(jpwm_cons, IOTJS_MAGIC_STRING_PROTOTYPE, + jprototype); + + jerry_release_value(jprototype); + + return jpwm_cons; } diff --git a/src/modules/iotjs_module_pwm.h b/src/modules/iotjs_module_pwm.h index 8bc0c3bbb5..728d1b9ab0 100644 --- a/src/modules/iotjs_module_pwm.h +++ b/src/modules/iotjs_module_pwm.h @@ -18,83 +18,38 @@ #define IOTJS_MODULE_PWM_H #include "iotjs_def.h" -#include "iotjs_objectwrap.h" -#include "iotjs_reqwrap.h" +#include "iotjs_module_periph_common.h" #if defined(__TIZENRT__) #include #include #endif - -typedef enum { - kPwmOpOpen, - kPwmOpSetDutyCycle, - kPwmOpSetPeriod, - kPwmOpSetFrequency, - kPwmOpSetEnable, - kPwmOpClose, -} PwmOp; - +// Forward declaration of platform data. These are only used by platform code. +// Generic PWM module never dereferences platform data pointer. +typedef struct iotjs_pwm_platform_data_s iotjs_pwm_platform_data_t; typedef struct { - iotjs_jobjectwrap_t jobjectwrap; + jerry_value_t jobject; + iotjs_pwm_platform_data_t* platform_data; -#if defined(__linux__) - int chip; - iotjs_string_t device; -#elif defined(__NUTTX__) - int device_fd; -#elif defined(__TIZENRT__) - iotbus_pwm_context_h ctx; -#endif uint32_t pin; double duty_cycle; double period; bool enable; -} IOTJS_VALIDATED_STRUCT(iotjs_pwm_t); - - -typedef bool (*pwm_func_ptr)(iotjs_pwm_t*); - - -typedef struct { - pwm_func_ptr caller; - bool result; - PwmOp op; -} iotjs_pwm_reqdata_t; - - -typedef struct { - iotjs_reqwrap_t reqwrap; - uv_work_t req; - iotjs_pwm_reqdata_t req_data; - iotjs_pwm_t* pwm_instance; -} IOTJS_VALIDATED_STRUCT(iotjs_pwm_reqwrap_t); - - -#define THIS iotjs_pwm_reqwrap_t* pwm_reqwrap - -iotjs_pwm_reqwrap_t* iotjs_pwm_reqwrap_from_request(uv_work_t* req); -iotjs_pwm_reqdata_t* iotjs_pwm_reqwrap_data(THIS); - -iotjs_pwm_t* iotjs_pwm_instance_from_reqwrap(THIS); - -#undef THIS - - -#define PWM_WORKER_INIT \ - iotjs_pwm_reqwrap_t* req_wrap = iotjs_pwm_reqwrap_from_request(work_req); \ - iotjs_pwm_reqdata_t* req_data = iotjs_pwm_reqwrap_data(req_wrap); \ - iotjs_pwm_t* pwm = iotjs_pwm_instance_from_reqwrap(req_wrap); - - -void iotjs_pwm_open_worker(uv_work_t* work_req); +} iotjs_pwm_t; +jerry_value_t iotjs_pwm_set_platform_config(iotjs_pwm_t* pwm, + const jerry_value_t jconfig); +bool iotjs_pwm_open(iotjs_pwm_t* pwm); bool iotjs_pwm_set_period(iotjs_pwm_t* pwm); bool iotjs_pwm_set_dutycycle(iotjs_pwm_t* pwm); bool iotjs_pwm_set_enable(iotjs_pwm_t* pwm); bool iotjs_pwm_close(iotjs_pwm_t* pwm); +// Platform-related functions; they are implemented +// by platform code (i.e.: linux, nuttx, tizen). +void iotjs_pwm_create_platform_data(iotjs_pwm_t* pwm); +void iotjs_pwm_destroy_platform_data(iotjs_pwm_platform_data_t* platform_data); #endif /* IOTJS_MODULE_PWM_H */ diff --git a/src/modules/iotjs_module_spi.c b/src/modules/iotjs_module_spi.c index 3c54a705cd..98aee63ace 100644 --- a/src/modules/iotjs_module_spi.c +++ b/src/modules/iotjs_module_spi.c @@ -16,437 +16,327 @@ #include "iotjs_def.h" #include "iotjs_module_spi.h" #include "iotjs_module_buffer.h" -#include "iotjs_objectwrap.h" -#include +#include "iotjs_uv_request.h" IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(spi); -static iotjs_spi_t* iotjs_spi_create(const iotjs_jval_t* jspi) { - iotjs_spi_t* spi = IOTJS_ALLOC(iotjs_spi_t); - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_spi_t, spi); - iotjs_jobjectwrap_initialize(&_this->jobjectwrap, jspi, - &this_module_native_info); - - _this->device = iotjs_string_create(""); - - return spi; -} - +IOTJS_DEFINE_PERIPH_CREATE_FUNCTION(spi); static void iotjs_spi_destroy(iotjs_spi_t* spi) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_spi_t, spi); - iotjs_jobjectwrap_destroy(&_this->jobjectwrap); - iotjs_string_destroy(&_this->device); + iotjs_spi_destroy_platform_data(spi->platform_data); IOTJS_RELEASE(spi); } - -#define THIS iotjs_spi_reqwrap_t* spi_reqwrap - - -static iotjs_spi_reqwrap_t* iotjs_spi_reqwrap_create( - const iotjs_jval_t* jcallback, iotjs_spi_t* spi, SpiOp op) { - iotjs_spi_reqwrap_t* spi_reqwrap = IOTJS_ALLOC(iotjs_spi_reqwrap_t); - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_spi_reqwrap_t, spi_reqwrap); - - iotjs_reqwrap_initialize(&_this->reqwrap, jcallback, (uv_req_t*)&_this->req); - - _this->req_data.op = op; - _this->spi_instance = spi; - - return spi_reqwrap; -} - - -static void iotjs_spi_reqwrap_destroy(THIS) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_spi_reqwrap_t, spi_reqwrap); - iotjs_reqwrap_destroy(&_this->reqwrap); - IOTJS_RELEASE(spi_reqwrap); -} - - -static void iotjs_spi_reqwrap_dispatched(THIS) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_spi_reqwrap_t, spi_reqwrap); - iotjs_spi_reqwrap_destroy(spi_reqwrap); -} - - -static uv_work_t* iotjs_spi_reqwrap_req(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_spi_reqwrap_t, spi_reqwrap); - return &_this->req; -} - - -static const iotjs_jval_t* iotjs_spi_reqwrap_jcallback(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_spi_reqwrap_t, spi_reqwrap); - return iotjs_reqwrap_jcallback(&_this->reqwrap); -} - - -iotjs_spi_reqwrap_t* iotjs_spi_reqwrap_from_request(uv_work_t* req) { - return (iotjs_spi_reqwrap_t*)(iotjs_reqwrap_from_request((uv_req_t*)req)); -} - - -iotjs_spi_reqdata_t* iotjs_spi_reqwrap_data(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_spi_reqwrap_t, spi_reqwrap); - return &_this->req_data; -} - - -iotjs_spi_t* iotjs_spi_instance_from_reqwrap(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_spi_reqwrap_t, spi_reqwrap); - return _this->spi_instance; -} - - -#undef THIS - - -static int iotjs_spi_get_array_data(char** buf, const iotjs_jval_t* jarray) { - iotjs_jval_t jlength = +static int spi_get_array_data(char** buf, jerry_value_t jarray) { + jerry_value_t jlength = iotjs_jval_get_property(jarray, IOTJS_MAGIC_STRING_LENGTH); - IOTJS_ASSERT(!iotjs_jval_is_undefined(&jlength)); + IOTJS_ASSERT(!jerry_value_is_undefined(jlength)); - size_t length = iotjs_jval_as_number(&jlength); + size_t length = iotjs_jval_as_number(jlength); IOTJS_ASSERT((int)length >= 0); *buf = iotjs_buffer_allocate(length); for (size_t i = 0; i < length; i++) { - iotjs_jval_t jdata = iotjs_jval_get_property_by_index(jarray, i); - (*buf)[i] = iotjs_jval_as_number(&jdata); - iotjs_jval_destroy(&jdata); + jerry_value_t jdata = iotjs_jval_get_property_by_index(jarray, i); + (*buf)[i] = iotjs_jval_as_number(jdata); + jerry_release_value(jdata); } - iotjs_jval_destroy(&jlength); + jerry_release_value(jlength); return (int)length; } - -static void iotjs_spi_set_array_buffer(iotjs_spi_t* spi, - const iotjs_jval_t* jtx_buf, - const iotjs_jval_t* jrx_buf) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_spi_t, spi); - - int tx_buf_len = iotjs_spi_get_array_data(&_this->tx_buf_data, jtx_buf); - int rx_buf_len = iotjs_spi_get_array_data(&_this->rx_buf_data, jrx_buf); - - IOTJS_ASSERT(_this->tx_buf_data != NULL && _this->rx_buf_data != NULL); - IOTJS_ASSERT(tx_buf_len > 0 && rx_buf_len > 0 && tx_buf_len == rx_buf_len); - - _this->buf_len = tx_buf_len; -} - - -static void iotjs_spi_set_buffer(iotjs_spi_t* spi, const iotjs_jval_t* jtx_buf, - const iotjs_jval_t* jrx_buf) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_spi_t, spi); - - iotjs_bufferwrap_t* tx_buf = iotjs_bufferwrap_from_jbuffer(jtx_buf); - iotjs_bufferwrap_t* rx_buf = iotjs_bufferwrap_from_jbuffer(jrx_buf); - - _this->tx_buf_data = iotjs_bufferwrap_buffer(tx_buf); - uint8_t tx_buf_len = iotjs_bufferwrap_length(tx_buf); - _this->rx_buf_data = iotjs_bufferwrap_buffer(rx_buf); - uint8_t rx_buf_len = iotjs_bufferwrap_length(rx_buf); - - IOTJS_ASSERT(_this->tx_buf_data != NULL && _this->rx_buf_data != NULL); - IOTJS_ASSERT(tx_buf_len > 0 && rx_buf_len > 0 && tx_buf_len == rx_buf_len); - - _this->buf_len = tx_buf_len; -} - - -static void iotjs_spi_release_buffer(iotjs_spi_t* spi) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_spi_t, spi); - - iotjs_buffer_release(_this->tx_buf_data); - iotjs_buffer_release(_this->rx_buf_data); -} - - -static void iotjs_spi_set_configuration(iotjs_spi_t* spi, - const iotjs_jval_t* joptions) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_spi_t, spi); - - iotjs_jval_t jdevice = - iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_DEVICE); - _this->device = iotjs_jval_as_string(&jdevice); - iotjs_jval_destroy(&jdevice); - - iotjs_jval_t jmode = +/* Default configuration: + *{ + * mode: spi.MODE[0], + * chipSelect: spi.CHIPSELECT.NONE, + * maxSpeed: 500000, + * bitsPerWord: 8, + * bitOrder: spi.BITORDER.MSB, + * loopback: false + * } + */ +static jerry_value_t spi_set_configuration(iotjs_spi_t* spi, + jerry_value_t joptions) { + jerry_value_t jmode = iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_MODE); - _this->mode = (SpiMode)iotjs_jval_as_number(&jmode); - iotjs_jval_destroy(&jmode); + if (jerry_value_is_undefined(jmode)) { + spi->mode = kSpiMode_0; + } else { + if (jerry_value_is_number(jmode)) { + spi->mode = (SpiMode)iotjs_jval_as_number(jmode); + } else { + spi->mode = __kSpiModeMax; + } - iotjs_jval_t jchip_select = + if (spi->mode >= __kSpiModeMax) { + return JS_CREATE_ERROR( + TYPE, "Bad arguments - mode should be MODE[0], [1], [2] or [3]"); + } + } + jerry_release_value(jmode); + + jerry_value_t jchip_select = iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_CHIPSELECT); - _this->chip_select = (SpiChipSelect)iotjs_jval_as_number(&jchip_select); - iotjs_jval_destroy(&jchip_select); + if (jerry_value_is_undefined(jchip_select)) { + spi->chip_select = kSpiCsNone; + } else { + if (jerry_value_is_number(jchip_select)) { + spi->chip_select = (SpiChipSelect)iotjs_jval_as_number(jchip_select); + } else { + spi->chip_select = __kSpiCsMax; + } + + if (spi->chip_select >= __kSpiCsMax) { + return JS_CREATE_ERROR( + TYPE, "Bad arguments - chipSelect should be CHIPSELECT.NONE or HIGH"); + } + } + jerry_release_value(jchip_select); - iotjs_jval_t jmax_speed = + jerry_value_t jmax_speed = iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_MAXSPEED); - _this->max_speed = iotjs_jval_as_number(&jmax_speed); - iotjs_jval_destroy(&jmax_speed); + if (jerry_value_is_undefined(jmax_speed)) { + spi->max_speed = 500000; + } else { + if (!jerry_value_is_number(jmax_speed)) { + return JS_CREATE_ERROR(TYPE, "Bad arguments - maxSpeed should be Number"); + } + spi->max_speed = iotjs_jval_as_number(jmax_speed); + } + jerry_release_value(jmax_speed); - iotjs_jval_t jbits_per_word = + jerry_value_t jbits_per_word = iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_BITSPERWORD); - _this->bits_per_word = (SpiOrder)iotjs_jval_as_number(&jbits_per_word); - iotjs_jval_destroy(&jbits_per_word); + if (jerry_value_is_undefined(jbits_per_word)) { + spi->bits_per_word = 8; + } else { + if (jerry_value_is_number(jbits_per_word)) { + spi->bits_per_word = iotjs_jval_as_number(jbits_per_word); + } else { + spi->bits_per_word = 0; + } + + if (spi->bits_per_word != 8 && spi->bits_per_word != 9) { + return JS_CREATE_ERROR(TYPE, + "Bad arguments - bitsPerWord should be 8 or 9"); + } + } + jerry_release_value(jbits_per_word); - iotjs_jval_t jbit_order = + jerry_value_t jbit_order = iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_BITORDER); - _this->bit_order = (SpiOrder)iotjs_jval_as_number(&jbit_order); - iotjs_jval_destroy(&jbit_order); + if (jerry_value_is_undefined(jbit_order)) { + spi->bit_order = kSpiOrderMsb; + } else { + if (jerry_value_is_number(jbit_order)) { + spi->bit_order = (SpiOrder)iotjs_jval_as_number(jbit_order); + } else { + spi->bit_order = __kSpiOrderMax; + } - iotjs_jval_t jloopback = + if (spi->bit_order >= __kSpiOrderMax) { + return JS_CREATE_ERROR( + TYPE, "Bad arguments - bitOrder should be BITORDER.MSB or LSB"); + } + } + jerry_release_value(jbit_order); + + jerry_value_t jloopback = iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_LOOPBACK); - _this->loopback = iotjs_jval_as_boolean(&jloopback); - iotjs_jval_destroy(&jloopback); -} + if (jerry_value_is_undefined(jloopback)) { + spi->loopback = false; + } else { + if (!jerry_value_is_boolean(jloopback)) { + return JS_CREATE_ERROR(TYPE, + "Bad arguments - loopback should be Boolean"); + } + spi->loopback = iotjs_jval_as_boolean(jloopback); + } + jerry_release_value(jloopback); + return jerry_create_undefined(); +} /* * SPI worker function */ -static void iotjs_spi_transfer_worker(uv_work_t* work_req) { - SPI_WORKER_INIT; - - if (!iotjs_spi_transfer(spi)) { - req_data->result = false; - return; - } - - req_data->result = true; -} - - -static void iotjs_spi_close_worker(uv_work_t* work_req) { - SPI_WORKER_INIT; - - if (!iotjs_spi_close(spi)) { - req_data->result = false; - return; +static void spi_worker(uv_work_t* work_req) { + iotjs_periph_data_t* worker_data = + (iotjs_periph_data_t*)IOTJS_UV_REQUEST_EXTRA_DATA(work_req); + iotjs_spi_t* spi = (iotjs_spi_t*)worker_data->data; + + switch (worker_data->op) { + case kSpiOpClose: { + worker_data->result = iotjs_spi_close(spi); + break; + } + case kSpiOpOpen: { + worker_data->result = iotjs_spi_open(spi); + break; + } + case kSpiOpTransferArray: + case kSpiOpTransferBuffer: { + worker_data->result = iotjs_spi_transfer(spi); + break; + } + default: + IOTJS_ASSERT(!"Invalid Operation"); } - - req_data->result = true; } +JS_FUNCTION(spi_constructor) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(1, object); + DJS_CHECK_ARG_IF_EXIST(1, function); -static void iotjs_spi_after_work(uv_work_t* work_req, int status) { - iotjs_spi_reqwrap_t* req_wrap = iotjs_spi_reqwrap_from_request(work_req); - iotjs_spi_reqdata_t* req_data = iotjs_spi_reqwrap_data(req_wrap); - iotjs_spi_t* spi = iotjs_spi_instance_from_reqwrap(req_wrap); - - iotjs_jargs_t jargs = iotjs_jargs_create(2); + // Create SPI object + jerry_value_t jspi = JS_GET_THIS(); + iotjs_spi_t* spi = spi_create(jspi); - bool result = req_data->result; + // Set configuration + jerry_value_t jconfig; + JS_GET_REQUIRED_ARG_VALUE(0, jconfig, IOTJS_MAGIC_STRING_CONFIG, object); - if (status) { - iotjs_jargs_append_error(&jargs, "System error"); - } else { - switch (req_data->op) { - case kSpiOpOpen: - if (!result) { - iotjs_jargs_append_error(&jargs, "Failed to export SPI device"); - } else { - iotjs_jargs_append_null(&jargs); - } - break; - case kSpiOpTransfer: - - if (!result) { - iotjs_jargs_append_error(&jargs, "Cannot transfer from SPI device"); - } else { - iotjs_jargs_append_null(&jargs); - - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_spi_t, spi); - - // Append read data - iotjs_jval_t result_data = - iotjs_jval_create_byte_array(_this->buf_len, _this->rx_buf_data); - iotjs_jargs_append_jval(&jargs, &result_data); - iotjs_jval_destroy(&result_data); - } - iotjs_spi_release_buffer(spi); - break; - case kSpiOpClose: - if (!result) { - iotjs_jargs_append_error(&jargs, "Failed to unexport SPI device"); - } else { - iotjs_jargs_append_null(&jargs); - } - break; - default: { - IOTJS_ASSERT(!"Unreachable"); - break; - } - } + jerry_value_t res = iotjs_spi_set_platform_config(spi, jconfig); + if (jerry_value_is_error(res)) { + return res; } + IOTJS_ASSERT(jerry_value_is_undefined(res)); - const iotjs_jval_t* jcallback = iotjs_spi_reqwrap_jcallback(req_wrap); - iotjs_make_callback(jcallback, iotjs_jval_get_undefined(), &jargs); + res = spi_set_configuration(spi, jconfig); + if (jerry_value_is_error(res)) { + return res; + } + IOTJS_ASSERT(jerry_value_is_undefined(res)); - iotjs_jargs_destroy(&jargs); - - iotjs_spi_reqwrap_dispatched(req_wrap); -} + jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(1, function); + // If the callback doesn't exist, it is completed synchronously. + // Otherwise, it will be executed asynchronously. + if (!jerry_value_is_null(jcallback)) { + iotjs_periph_call_async(spi, jcallback, kSpiOpOpen, spi_worker); + } else if (!iotjs_spi_open(spi)) { + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kSpiOpOpen)); + } -iotjs_spi_t* iotjs_spi_get_instance(const iotjs_jval_t* jspi) { - uintptr_t handle = iotjs_jval_get_object_native_handle(jspi); - return (iotjs_spi_t*)(handle); + return jerry_create_undefined(); } +static uint8_t spi_transfer_helper(jerry_value_t jtx_buf, iotjs_spi_t* spi) { + uint8_t result = kSpiOpTransferBuffer; + if (jerry_value_is_array(jtx_buf)) { + spi->buf_len = spi_get_array_data(&spi->tx_buf_data, jtx_buf); + result = kSpiOpTransferArray; + } else if (jerry_value_is_object(jtx_buf)) { + iotjs_bufferwrap_t* tx_buf = iotjs_bufferwrap_from_jbuffer(jtx_buf); -#define SPI_ASYNC(call, this, jcallback, op) \ - do { \ - uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get()); \ - iotjs_spi_reqwrap_t* req_wrap = \ - iotjs_spi_reqwrap_create(jcallback, this, op); \ - uv_work_t* req = iotjs_spi_reqwrap_req(req_wrap); \ - uv_queue_work(loop, req, iotjs_spi_##call##_worker, iotjs_spi_after_work); \ - } while (0) - - -JHANDLER_FUNCTION(SpiConstructor) { - DJHANDLER_CHECK_THIS(object); - DJHANDLER_CHECK_ARGS(2, object, function); - - // Create SPI object - const iotjs_jval_t* jspi = JHANDLER_GET_THIS(object); - iotjs_spi_t* spi = iotjs_spi_create(jspi); - IOTJS_ASSERT(spi == iotjs_spi_get_instance(jspi)); + spi->tx_buf_data = tx_buf->buffer; + spi->buf_len = iotjs_bufferwrap_length(tx_buf); + } - // Set configuration - const iotjs_jval_t* jconfiguration = JHANDLER_GET_ARG(0, object); - iotjs_spi_set_configuration(spi, jconfiguration); + IOTJS_ASSERT(spi->buf_len > 0); + spi->rx_buf_data = iotjs_buffer_allocate(spi->buf_len); + IOTJS_ASSERT(spi->tx_buf_data != NULL && spi->rx_buf_data != NULL); - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG(1, function); - SPI_ASYNC(open, spi, jcallback, kSpiOpOpen); + return result; } - // FIXME: do not need transferArray if array buffer is implemented. -JHANDLER_FUNCTION(TransferArray) { - JHANDLER_DECLARE_THIS_PTR(spi, spi); - - DJHANDLER_CHECK_ARGS(2, array, array); - DJHANDLER_CHECK_ARG_IF_EXIST(2, function); - - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(2, function); - - iotjs_spi_set_array_buffer(spi, JHANDLER_GET_ARG(0, array), - JHANDLER_GET_ARG(1, array)); +JS_FUNCTION(spi_transfer) { + JS_DECLARE_THIS_PTR(spi, spi); + DJS_CHECK_ARG_IF_EXIST(1, function); - if (jcallback) { - SPI_ASYNC(transfer, spi, jcallback, kSpiOpTransfer); - } else { - if (!iotjs_spi_transfer(spi)) { - JHANDLER_THROW(COMMON, "SPI Transfer Error"); - } else { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_spi_t, spi); + uint8_t op = spi_transfer_helper(jargv[0], spi); + iotjs_periph_call_async(spi, JS_GET_ARG_IF_EXIST(1, function), op, + spi_worker); - iotjs_jval_t result = - iotjs_jval_create_byte_array(_this->buf_len, _this->rx_buf_data); - iotjs_jhandler_return_jval(jhandler, &result); - iotjs_jval_destroy(&result); - } - } + return jerry_create_undefined(); } +JS_FUNCTION(spi_transfer_sync) { + JS_DECLARE_THIS_PTR(spi, spi); -JHANDLER_FUNCTION(TransferBuffer) { - JHANDLER_DECLARE_THIS_PTR(spi, spi); - - DJHANDLER_CHECK_ARGS(2, object, object); - DJHANDLER_CHECK_ARG_IF_EXIST(2, function); + uint8_t op = spi_transfer_helper(jargv[0], spi); - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(2, function); - - iotjs_spi_set_buffer(spi, JHANDLER_GET_ARG(0, object), - JHANDLER_GET_ARG(1, object)); - - if (jcallback) { - SPI_ASYNC(transfer, spi, jcallback, kSpiOpTransfer); + jerry_value_t result = jerry_create_undefined(); + if (!iotjs_spi_transfer(spi)) { + result = JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(op)); } else { - if (!iotjs_spi_transfer(spi)) { - JHANDLER_THROW(COMMON, "SPI Transfer Error"); - } else { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_spi_t, spi); + result = iotjs_jval_create_byte_array(spi->buf_len, spi->rx_buf_data); + } - iotjs_jval_t result = - iotjs_jval_create_byte_array(_this->buf_len, _this->rx_buf_data); - iotjs_jhandler_return_jval(jhandler, &result); - iotjs_jval_destroy(&result); - } + if (op == kSpiOpTransferArray) { + IOTJS_RELEASE(spi->tx_buf_data); } + + IOTJS_RELEASE(spi->rx_buf_data); + + return result; } +JS_FUNCTION(spi_close) { + JS_DECLARE_THIS_PTR(spi, spi); + DJS_CHECK_ARG_IF_EXIST(1, function); -JHANDLER_FUNCTION(Close) { - JHANDLER_DECLARE_THIS_PTR(spi, spi); + iotjs_periph_call_async(spi, JS_GET_ARG_IF_EXIST(0, function), kSpiOpClose, + spi_worker); - DJHANDLER_CHECK_ARG_IF_EXIST(0, function); + return jerry_create_undefined(); +} - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(0, function); +JS_FUNCTION(spi_close_sync) { + JS_DECLARE_THIS_PTR(spi, spi); - if (jcallback) { - SPI_ASYNC(close, spi, jcallback, kSpiOpClose); - } else { - if (!iotjs_spi_close(spi)) { - JHANDLER_THROW(COMMON, "SPI Close Error"); - } + if (!iotjs_spi_close(spi)) { + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kSpiOpClose)); } - iotjs_jhandler_return_null(jhandler); + return jerry_create_undefined(); } +jerry_value_t iotjs_init_spi(void) { + jerry_value_t jspi_cons = jerry_create_external_function(spi_constructor); -iotjs_jval_t InitSpi() { - iotjs_jval_t jspi = iotjs_jval_create_object(); - iotjs_jval_t jspiConstructor = - iotjs_jval_create_function_with_dispatch(SpiConstructor); - iotjs_jval_set_property_jval(&jspi, IOTJS_MAGIC_STRING_SPI, &jspiConstructor); + jerry_value_t prototype = jerry_create_object(); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_CLOSE, spi_close); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_CLOSESYNC, + spi_close_sync); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_TRANSFER, spi_transfer); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_TRANSFERSYNC, + spi_transfer_sync); - iotjs_jval_t prototype = iotjs_jval_create_object(); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_TRANSFERARRAY, - TransferArray); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_TRANSFERBUFFER, - TransferBuffer); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_CLOSE, Close); - iotjs_jval_set_property_jval(&jspiConstructor, IOTJS_MAGIC_STRING_PROTOTYPE, - &prototype); - iotjs_jval_destroy(&prototype); - iotjs_jval_destroy(&jspiConstructor); + iotjs_jval_set_property_jval(jspi_cons, IOTJS_MAGIC_STRING_PROTOTYPE, + prototype); + jerry_release_value(prototype); // SPI mode properties - iotjs_jval_t jmode = iotjs_jval_create_object(); - iotjs_jval_set_property_number(&jmode, IOTJS_MAGIC_STRING_0, kSpiMode_0); - iotjs_jval_set_property_number(&jmode, IOTJS_MAGIC_STRING_1, kSpiMode_1); - iotjs_jval_set_property_number(&jmode, IOTJS_MAGIC_STRING_2, kSpiMode_2); - iotjs_jval_set_property_number(&jmode, IOTJS_MAGIC_STRING_3, kSpiMode_3); - iotjs_jval_set_property_jval(&jspi, IOTJS_MAGIC_STRING_MODE_U, &jmode); - iotjs_jval_destroy(&jmode); + jerry_value_t jmode = jerry_create_object(); + iotjs_jval_set_property_number(jmode, IOTJS_MAGIC_STRING_0, kSpiMode_0); + iotjs_jval_set_property_number(jmode, IOTJS_MAGIC_STRING_1, kSpiMode_1); + iotjs_jval_set_property_number(jmode, IOTJS_MAGIC_STRING_2, kSpiMode_2); + iotjs_jval_set_property_number(jmode, IOTJS_MAGIC_STRING_3, kSpiMode_3); + iotjs_jval_set_property_jval(jspi_cons, IOTJS_MAGIC_STRING_MODE_U, jmode); + jerry_release_value(jmode); // SPI mode properties - iotjs_jval_t jcs = iotjs_jval_create_object(); - iotjs_jval_set_property_number(&jcs, IOTJS_MAGIC_STRING_NONE, kSpiCsNone); - iotjs_jval_set_property_number(&jcs, IOTJS_MAGIC_STRING_HIGH, kSpiCsHigh); - iotjs_jval_set_property_jval(&jspi, IOTJS_MAGIC_STRING_CHIPSELECT_U, &jcs); - iotjs_jval_destroy(&jcs); + jerry_value_t jcs = jerry_create_object(); + iotjs_jval_set_property_number(jcs, IOTJS_MAGIC_STRING_NONE_U, kSpiCsNone); + iotjs_jval_set_property_number(jcs, IOTJS_MAGIC_STRING_HIGH_U, kSpiCsHigh); + iotjs_jval_set_property_jval(jspi_cons, IOTJS_MAGIC_STRING_CHIPSELECT_U, jcs); + jerry_release_value(jcs); // SPI order properties - iotjs_jval_t jbit_order = iotjs_jval_create_object(); - iotjs_jval_set_property_number(&jbit_order, IOTJS_MAGIC_STRING_MSB, + jerry_value_t jbit_order = jerry_create_object(); + iotjs_jval_set_property_number(jbit_order, IOTJS_MAGIC_STRING_MSB, kSpiOrderMsb); - iotjs_jval_set_property_number(&jbit_order, IOTJS_MAGIC_STRING_LSB, + iotjs_jval_set_property_number(jbit_order, IOTJS_MAGIC_STRING_LSB, kSpiOrderLsb); - iotjs_jval_set_property_jval(&jspi, IOTJS_MAGIC_STRING_BITORDER_U, - &jbit_order); - iotjs_jval_destroy(&jbit_order); + iotjs_jval_set_property_jval(jspi_cons, IOTJS_MAGIC_STRING_BITORDER_U, + jbit_order); + jerry_release_value(jbit_order); - return jspi; + return jspi_cons; } diff --git a/src/modules/iotjs_module_spi.h b/src/modules/iotjs_module_spi.h index b4349f3656..2eb2eb3867 100644 --- a/src/modules/iotjs_module_spi.h +++ b/src/modules/iotjs_module_spi.h @@ -19,35 +19,28 @@ #include "iotjs_def.h" #include "iotjs_module_buffer.h" -#include "iotjs_objectwrap.h" -#include "iotjs_reqwrap.h" +#include "iotjs_module_periph_common.h" -typedef enum { - kSpiOpOpen, - kSpiOpTransfer, - kSpiOpClose, -} SpiOp; - typedef enum { kSpiMode_0, kSpiMode_1, kSpiMode_2, kSpiMode_3, + __kSpiModeMax } SpiMode; -typedef enum { - kSpiCsNone, - kSpiCsHigh, -} SpiChipSelect; - -typedef enum { kSpiOrderMsb, kSpiOrderLsb } SpiOrder; +typedef enum { kSpiCsNone, kSpiCsHigh, __kSpiCsMax } SpiChipSelect; +typedef enum { kSpiOrderMsb, kSpiOrderLsb, __kSpiOrderMax } SpiOrder; +// Forward declaration of platform data. These are only used by platform code. +// Generic SPI module never dereferences platform data pointer. +typedef struct iotjs_spi_platform_data_s iotjs_spi_platform_data_t; +// This SPI class provides interfaces for SPI operation. typedef struct { - iotjs_jobjectwrap_t jobjectwrap; - iotjs_string_t device; - int32_t device_fd; + jerry_value_t jobject; + iotjs_spi_platform_data_t* platform_data; SpiMode mode; SpiChipSelect chip_select; @@ -61,44 +54,17 @@ typedef struct { char* tx_buf_data; char* rx_buf_data; uint8_t buf_len; +} iotjs_spi_t; -} IOTJS_VALIDATED_STRUCT(iotjs_spi_t); - - -typedef struct { - bool result; - SpiOp op; -} iotjs_spi_reqdata_t; - - -typedef struct { - iotjs_reqwrap_t reqwrap; - uv_work_t req; - iotjs_spi_reqdata_t req_data; - iotjs_spi_t* spi_instance; -} IOTJS_VALIDATED_STRUCT(iotjs_spi_reqwrap_t); - - -#define THIS iotjs_spi_reqwrap_t* spi_reqwrap - -iotjs_spi_reqwrap_t* iotjs_spi_reqwrap_from_request(uv_work_t* req); -iotjs_spi_reqdata_t* iotjs_spi_reqwrap_data(THIS); - -iotjs_spi_t* iotjs_spi_instance_from_reqwrap(THIS); - -#undef THIS - - -#define SPI_WORKER_INIT \ - iotjs_spi_reqwrap_t* req_wrap = iotjs_spi_reqwrap_from_request(work_req); \ - iotjs_spi_reqdata_t* req_data = iotjs_spi_reqwrap_data(req_wrap); \ - iotjs_spi_t* spi = iotjs_spi_instance_from_reqwrap(req_wrap); - - +jerry_value_t iotjs_spi_set_platform_config(iotjs_spi_t* spi, + const jerry_value_t jconfig); +bool iotjs_spi_open(iotjs_spi_t* spi); bool iotjs_spi_transfer(iotjs_spi_t* spi); bool iotjs_spi_close(iotjs_spi_t* spi); -void iotjs_spi_open_worker(uv_work_t* work_req); - +// Platform-related functions; they are implemented +// by platform code (i.e.: linux, nuttx, tizen). +void iotjs_spi_create_platform_data(iotjs_spi_t* spi); +void iotjs_spi_destroy_platform_data(iotjs_spi_platform_data_t* pdata); #endif /* IOTJS_MODULE_SPI_H */ diff --git a/src/modules/iotjs_module_stm32f4dis.c b/src/modules/iotjs_module_stm32f4dis.c index 672a504af1..19598394fe 100644 --- a/src/modules/iotjs_module_stm32f4dis.c +++ b/src/modules/iotjs_module_stm32f4dis.c @@ -17,12 +17,12 @@ #include "iotjs_module_stm32f4dis.h" -iotjs_jval_t InitStm32f4dis() { - iotjs_jval_t stm32f4dis = iotjs_jval_create_object(); +jerry_value_t iotjs_init_stm32f4dis() { + jerry_value_t stm32f4dis = jerry_create_object(); #if defined(__NUTTX__) - iotjs_stm32f4dis_pin_initialize(&stm32f4dis); + iotjs_stm32f4dis_pin_initialize(stm32f4dis); #endif diff --git a/src/modules/iotjs_module_stm32f4dis.h b/src/modules/iotjs_module_stm32f4dis.h index f14d608d03..716273d328 100644 --- a/src/modules/iotjs_module_stm32f4dis.h +++ b/src/modules/iotjs_module_stm32f4dis.h @@ -17,7 +17,7 @@ #define IOTJS_MODULE_STM32F4DIS_H -void iotjs_stm32f4dis_pin_initialize(const iotjs_jval_t* jobj); +void iotjs_stm32f4dis_pin_initialize(jerry_value_t jobj); #endif /* IOTJS_MODULE_STM32F4DIS_H */ diff --git a/src/iotjs_exception.c b/src/modules/iotjs_module_stm32f7nucleo.c similarity index 62% rename from src/iotjs_exception.c rename to src/modules/iotjs_module_stm32f7nucleo.c index bad8c26189..f398997c3b 100644 --- a/src/iotjs_exception.c +++ b/src/modules/iotjs_module_stm32f7nucleo.c @@ -1,4 +1,4 @@ -/* Copyright 2015-present Samsung Electronics Co., Ltd. and other contributors +/* Copyright 2019-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. @@ -13,17 +13,18 @@ * limitations under the License. */ - #include "iotjs_def.h" -#include "iotjs_exception.h" +#include "iotjs_module_stm32f7nucleo.h" + -#include +jerry_value_t iotjs_init_stm32f7nucleo() { + jerry_value_t stm32f7nucleo = jerry_create_object(); +/* Hardware support in progress, do initialization here */ -#include "uv.h" +#if defined(__NUTTX__) + iotjs_stm32f7nucleo_pin_initialize(stm32f7nucleo); -iotjs_jval_t iotjs_create_uv_exception(int errorno, const char* syscall) { - static char msg[256]; - snprintf(msg, sizeof(msg), "'%s' %s", syscall, uv_strerror(errorno)); - return iotjs_jval_create_error(msg); +#endif + return stm32f7nucleo; } diff --git a/src/modules/iotjs_module_stm32f7nucleo.h b/src/modules/iotjs_module_stm32f7nucleo.h new file mode 100644 index 0000000000..1c31d9fdfa --- /dev/null +++ b/src/modules/iotjs_module_stm32f7nucleo.h @@ -0,0 +1,23 @@ +/* Copyright 2019-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_STM32F4DIS_H +#define IOTJS_MODULE_STM32F4DIS_H + + +void iotjs_stm32f7nucleo_pin_initialize(jerry_value_t jobj); + + +#endif /* IOTJS_MODULE_STM32F4DIS_H */ diff --git a/src/modules/iotjs_module_tcp.c b/src/modules/iotjs_module_tcp.c index aa210b9193..1878d261b2 100644 --- a/src/modules/iotjs_module_tcp.c +++ b/src/modules/iotjs_module_tcp.c @@ -17,235 +17,71 @@ #include "iotjs_def.h" #include "iotjs_module_tcp.h" -#include "iotjs_handlewrap.h" #include "iotjs_module_buffer.h" -#include "iotjs_reqwrap.h" +#include "iotjs_uv_handle.h" +#include "iotjs_uv_request.h" +static const jerry_object_native_info_t this_module_native_info = { NULL }; -IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(tcpwrap); - -iotjs_tcpwrap_t* iotjs_tcpwrap_create(const iotjs_jval_t* jtcp) { - iotjs_tcpwrap_t* tcpwrap = IOTJS_ALLOC(iotjs_tcpwrap_t); - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_tcpwrap_t, tcpwrap); - - iotjs_handlewrap_initialize(&_this->handlewrap, jtcp, - (uv_handle_t*)(&_this->handle), - &this_module_native_info); +void iotjs_tcp_object_init(jerry_value_t jtcp) { + // uv_tcp_t* can be handled as uv_handle_t* or even as uv_stream_t* + uv_handle_t* handle = iotjs_uv_handle_create(sizeof(uv_tcp_t), jtcp, + &this_module_native_info, 0); const iotjs_environment_t* env = iotjs_environment_get(); - uv_tcp_init(iotjs_environment_loop(env), &_this->handle); - - return tcpwrap; -} - - -static void iotjs_tcpwrap_destroy(iotjs_tcpwrap_t* tcpwrap) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_tcpwrap_t, tcpwrap); - iotjs_handlewrap_destroy(&_this->handlewrap); - IOTJS_RELEASE(tcpwrap); -} - - -iotjs_tcpwrap_t* iotjs_tcpwrap_from_handle(uv_tcp_t* tcp_handle) { - uv_handle_t* handle = (uv_handle_t*)(tcp_handle); - iotjs_handlewrap_t* handlewrap = iotjs_handlewrap_from_handle(handle); - iotjs_tcpwrap_t* tcpwrap = (iotjs_tcpwrap_t*)handlewrap; - IOTJS_ASSERT(iotjs_tcpwrap_tcp_handle(tcpwrap) == tcp_handle); - return tcpwrap; -} - - -iotjs_tcpwrap_t* iotjs_tcpwrap_from_jobject(const iotjs_jval_t* jtcp) { - iotjs_handlewrap_t* handlewrap = iotjs_handlewrap_from_jobject(jtcp); - return (iotjs_tcpwrap_t*)handlewrap; -} - - -uv_tcp_t* iotjs_tcpwrap_tcp_handle(iotjs_tcpwrap_t* tcpwrap) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_tcpwrap_t, tcpwrap); - uv_handle_t* handle = iotjs_handlewrap_get_uv_handle(&_this->handlewrap); - return (uv_tcp_t*)handle; -} - - -iotjs_jval_t* iotjs_tcpwrap_jobject(iotjs_tcpwrap_t* tcpwrap) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_tcpwrap_t, tcpwrap); - return iotjs_handlewrap_jobject(&_this->handlewrap); -} - - -#define THIS iotjs_connect_reqwrap_t* connect_reqwrap - - -static void iotjs_connect_reqwrap_destroy(THIS); - - -iotjs_connect_reqwrap_t* iotjs_connect_reqwrap_create( - const iotjs_jval_t* jcallback) { - iotjs_connect_reqwrap_t* connect_reqwrap = - IOTJS_ALLOC(iotjs_connect_reqwrap_t); - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_connect_reqwrap_t, connect_reqwrap); - iotjs_reqwrap_initialize(&_this->reqwrap, jcallback, (uv_req_t*)&_this->req); - return connect_reqwrap; -} - - -static void iotjs_connect_reqwrap_destroy(THIS) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_connect_reqwrap_t, connect_reqwrap); - iotjs_reqwrap_destroy(&_this->reqwrap); - IOTJS_RELEASE(connect_reqwrap); -} - - -void iotjs_connect_reqwrap_dispatched(THIS) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_connect_reqwrap_t, - connect_reqwrap); - iotjs_connect_reqwrap_destroy(connect_reqwrap); + uv_tcp_init(iotjs_environment_loop(env), (uv_tcp_t*)handle); } -uv_connect_t* iotjs_connect_reqwrap_req(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_connect_reqwrap_t, connect_reqwrap); - return &_this->req; -} - - -const iotjs_jval_t* iotjs_connect_reqwrap_jcallback(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_connect_reqwrap_t, connect_reqwrap); - return iotjs_reqwrap_jcallback(&_this->reqwrap); -} - -#undef THIS - - -#define THIS iotjs_write_reqwrap_t* write_reqwrap - - -static void iotjs_write_reqwrap_destroy(THIS); - - -iotjs_write_reqwrap_t* iotjs_write_reqwrap_create( - const iotjs_jval_t* jcallback) { - iotjs_write_reqwrap_t* write_reqwrap = IOTJS_ALLOC(iotjs_write_reqwrap_t); - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_write_reqwrap_t, write_reqwrap); - iotjs_reqwrap_initialize(&_this->reqwrap, jcallback, (uv_req_t*)&_this->req); - return write_reqwrap; -} - - -static void iotjs_write_reqwrap_destroy(THIS) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_write_reqwrap_t, write_reqwrap); - iotjs_reqwrap_destroy(&_this->reqwrap); - IOTJS_RELEASE(write_reqwrap); -} - - -void iotjs_write_reqwrap_dispatched(THIS) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_write_reqwrap_t, - write_reqwrap); - iotjs_write_reqwrap_destroy(write_reqwrap); -} - - -uv_write_t* iotjs_write_reqwrap_req(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_write_reqwrap_t, write_reqwrap); - return &_this->req; -} - - -const iotjs_jval_t* iotjs_write_reqwrap_jcallback(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_write_reqwrap_t, write_reqwrap); - return iotjs_reqwrap_jcallback(&_this->reqwrap); -} - -#undef THIS - - -#define THIS iotjs_shutdown_reqwrap_t* shutdown_reqwrap - - -static void iotjs_shutdown_reqwrap_destroy(THIS); - - -iotjs_shutdown_reqwrap_t* iotjs_shutdown_reqwrap_create( - const iotjs_jval_t* jcallback) { - iotjs_shutdown_reqwrap_t* shutdown_reqwrap = - IOTJS_ALLOC(iotjs_shutdown_reqwrap_t); - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_shutdown_reqwrap_t, - shutdown_reqwrap); - iotjs_reqwrap_initialize(&_this->reqwrap, jcallback, (uv_req_t*)&_this->req); - return shutdown_reqwrap; -} - - -static void iotjs_shutdown_reqwrap_destroy(THIS) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_shutdown_reqwrap_t, shutdown_reqwrap); - iotjs_reqwrap_destroy(&_this->reqwrap); - IOTJS_RELEASE(shutdown_reqwrap); -} - - -void iotjs_shutdown_reqwrap_dispatched(THIS) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_shutdown_reqwrap_t, - shutdown_reqwrap); - iotjs_shutdown_reqwrap_destroy(shutdown_reqwrap); -} +static void iotjs_tcp_report_req_result(uv_req_t* req, int status) { + IOTJS_ASSERT(req != NULL); + // Take callback function object. + jerry_value_t jcallback = *IOTJS_UV_REQUEST_JSCALLBACK(req); + // Only parameter is status code. + jerry_value_t jstatus = jerry_create_number(status); -uv_shutdown_t* iotjs_shutdown_reqwrap_req(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_shutdown_reqwrap_t, shutdown_reqwrap); - return &_this->req; -} + // Make callback. + iotjs_invoke_callback(jcallback, jerry_create_undefined(), &jstatus, 1); + // Destroy args + jerry_release_value(jstatus); -const iotjs_jval_t* iotjs_shutdown_reqwrap_jcallback(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_shutdown_reqwrap_t, shutdown_reqwrap); - return iotjs_reqwrap_jcallback(&_this->reqwrap); + // Release request. + iotjs_uv_request_destroy(req); } -#undef THIS - - -JHANDLER_FUNCTION(TCP) { - DJHANDLER_CHECK_THIS(object); - DJHANDLER_CHECK_ARGS(0); - - const iotjs_jval_t* jtcp = JHANDLER_GET_THIS(object); - iotjs_tcpwrap_t* tcp_wrap = iotjs_tcpwrap_create(jtcp); - IOTJS_UNUSED(tcp_wrap); -} +JS_FUNCTION(tcp_constructor) { + DJS_CHECK_THIS(); -JHANDLER_FUNCTION(Open) { + jerry_value_t jtcp = JS_GET_THIS(); + iotjs_tcp_object_init(jtcp); + return jerry_create_undefined(); } // Socket close result handler. -void AfterClose(uv_handle_t* handle) { - iotjs_handlewrap_t* wrap = iotjs_handlewrap_from_handle(handle); - - // tcp object. - const iotjs_jval_t* jtcp = iotjs_handlewrap_jobject(wrap); +void after_close(uv_handle_t* handle) { + jerry_value_t jtcp = IOTJS_UV_HANDLE_DATA(handle)->jobject; // callback function. - iotjs_jval_t jcallback = + jerry_value_t jcallback = iotjs_jval_get_property(jtcp, IOTJS_MAGIC_STRING_ONCLOSE); - if (iotjs_jval_is_function(&jcallback)) { - iotjs_make_callback(&jcallback, iotjs_jval_get_undefined(), - iotjs_jargs_get_empty()); + if (jerry_value_is_function(jcallback)) { + iotjs_invoke_callback(jcallback, jerry_create_undefined(), NULL, 0); } - iotjs_jval_destroy(&jcallback); + jerry_release_value(jcallback); } // Close socket -JHANDLER_FUNCTION(Close) { - JHANDLER_DECLARE_THIS_PTR(handlewrap, wrap); - DJHANDLER_CHECK_ARGS(0); +JS_FUNCTION(tcp_close) { + JS_DECLARE_PTR(jthis, uv_handle_t, uv_handle); - // close uv handle, `AfterClose` will be called after socket closed. - iotjs_handlewrap_close(wrap, AfterClose); + iotjs_uv_handle_close(uv_handle, after_close); + return jerry_create_undefined(); } @@ -253,86 +89,65 @@ JHANDLER_FUNCTION(Close) { // start listening. // [0] address // [1] port -JHANDLER_FUNCTION(Bind) { - JHANDLER_DECLARE_THIS_PTR(tcpwrap, tcp_wrap); +JS_FUNCTION(tcp_bind) { + JS_DECLARE_PTR(jthis, uv_tcp_t, tcp_handle); - DJHANDLER_CHECK_ARGS(2, string, number); + DJS_CHECK_ARGS(2, string, number); - iotjs_string_t address = JHANDLER_GET_ARG(0, string); - int port = JHANDLER_GET_ARG(1, number); + iotjs_string_t address = JS_GET_ARG(0, string); + int port = JS_GET_ARG(1, number); sockaddr_in addr; int err = uv_ip4_addr(iotjs_string_data(&address), port, &addr); if (err == 0) { - err = uv_tcp_bind(iotjs_tcpwrap_tcp_handle(tcp_wrap), - (const sockaddr*)(&addr), 0); + err = uv_tcp_bind(tcp_handle, (const sockaddr*)(&addr), 0); } - iotjs_jhandler_return_number(jhandler, err); - iotjs_string_destroy(&address); + + return jerry_create_number(err); } // Connection request result handler. -static void AfterConnect(uv_connect_t* req, int status) { - iotjs_connect_reqwrap_t* req_wrap = (iotjs_connect_reqwrap_t*)(req->data); - IOTJS_ASSERT(req_wrap != NULL); - - // Take callback function object. - // function afterConnect(status) - const iotjs_jval_t* jcallback = iotjs_connect_reqwrap_jcallback(req_wrap); - IOTJS_ASSERT(iotjs_jval_is_function(jcallback)); - - // Only parameter is status code. - iotjs_jargs_t args = iotjs_jargs_create(1); - iotjs_jargs_append_number(&args, status); - - // Make callback. - iotjs_make_callback(jcallback, iotjs_jval_get_undefined(), &args); - - // Destroy args - iotjs_jargs_destroy(&args); - - // Release request wrapper. - iotjs_connect_reqwrap_dispatched(req_wrap); +static void after_connect(uv_connect_t* req, int status) { + iotjs_tcp_report_req_result((uv_req_t*)req, status); } - // Create a connection using the socket. // [0] address // [1] port // [2] callback -JHANDLER_FUNCTION(Connect) { - JHANDLER_DECLARE_THIS_PTR(tcpwrap, tcp_wrap); +JS_FUNCTION(tcp_connect) { + JS_DECLARE_PTR(jthis, uv_tcp_t, tcp_handle); - DJHANDLER_CHECK_ARGS(3, string, number, function); + DJS_CHECK_ARGS(3, string, number, function); - iotjs_string_t address = JHANDLER_GET_ARG(0, string); - int port = JHANDLER_GET_ARG(1, number); - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG(2, function); + iotjs_string_t address = JS_GET_ARG(0, string); + int port = JS_GET_ARG(1, number); + jerry_value_t jcallback = JS_GET_ARG(2, function); sockaddr_in addr; int err = uv_ip4_addr(iotjs_string_data(&address), port, &addr); if (err == 0) { - // Create connection request wrapper. - iotjs_connect_reqwrap_t* req_wrap = iotjs_connect_reqwrap_create(jcallback); + // Create connection request and configure request data. + uv_req_t* req_connect = + iotjs_uv_request_create(sizeof(uv_connect_t), jcallback, 0); // Create connection request. - err = uv_tcp_connect(iotjs_connect_reqwrap_req(req_wrap), - iotjs_tcpwrap_tcp_handle(tcp_wrap), - (const sockaddr*)(&addr), AfterConnect); + err = uv_tcp_connect((uv_connect_t*)req_connect, tcp_handle, + (const sockaddr*)(&addr), after_connect); if (err) { - iotjs_connect_reqwrap_dispatched(req_wrap); + iotjs_uv_request_destroy(req_connect); } } - iotjs_jhandler_return_number(jhandler, err); - iotjs_string_destroy(&address); + + return jerry_create_number(err); } @@ -340,124 +155,98 @@ JHANDLER_FUNCTION(Connect) { // Parameters: // * uv_stream_t* handle - server handle // * int status - status code -static void OnConnection(uv_stream_t* handle, int status) { - // Server tcp wrapper. - iotjs_tcpwrap_t* tcp_wrap = iotjs_tcpwrap_from_handle((uv_tcp_t*)handle); - - // Tcp object - const iotjs_jval_t* jtcp = iotjs_tcpwrap_jobject(tcp_wrap); +static void on_connection(uv_stream_t* handle, int status) { + jerry_value_t jtcp = IOTJS_UV_HANDLE_DATA(handle)->jobject; // `onconnection` callback. - iotjs_jval_t jonconnection = + jerry_value_t jonconnection = iotjs_jval_get_property(jtcp, IOTJS_MAGIC_STRING_ONCONNECTION); - IOTJS_ASSERT(iotjs_jval_is_function(&jonconnection)); + IOTJS_ASSERT(jerry_value_is_function(jonconnection)); // The callback takes two parameter // [0] status // [1] client tcp object - iotjs_jargs_t args = iotjs_jargs_create(2); - iotjs_jargs_append_number(&args, status); + size_t argc = 1; + jerry_value_t args[2] = { jerry_create_number(status), 0 }; if (status == 0) { // Create client socket handle wrapper. - iotjs_jval_t jcreate_tcp = + jerry_value_t jcreate_tcp = iotjs_jval_get_property(jtcp, IOTJS_MAGIC_STRING_CREATETCP); - IOTJS_ASSERT(iotjs_jval_is_function(&jcreate_tcp)); + IOTJS_ASSERT(jerry_value_is_function(jcreate_tcp)); - iotjs_jval_t jclient_tcp = - iotjs_jhelper_call_ok(&jcreate_tcp, iotjs_jval_get_undefined(), - iotjs_jargs_get_empty()); - IOTJS_ASSERT(iotjs_jval_is_object(&jclient_tcp)); + jerry_value_t jclient_tcp = + jerry_call_function(jcreate_tcp, jerry_create_undefined(), NULL, 0); + IOTJS_ASSERT(!jerry_value_is_error(jclient_tcp)); + IOTJS_ASSERT(jerry_value_is_object(jclient_tcp)); - iotjs_tcpwrap_t* tcp_wrap_client = - (iotjs_tcpwrap_t*)(iotjs_jval_get_object_native_handle(&jclient_tcp)); + void* client_handle = NULL; + bool has_client_handle = + jerry_get_object_native_pointer(jclient_tcp, &client_handle, + &this_module_native_info); - uv_stream_t* client_handle = - (uv_stream_t*)(iotjs_tcpwrap_tcp_handle(tcp_wrap_client)); - int err = uv_accept(handle, client_handle); - if (err) { + if (!has_client_handle || uv_accept(handle, (uv_stream_t*)client_handle)) { + jerry_release_value(args[0]); return; } - iotjs_jargs_append_jval(&args, &jclient_tcp); - iotjs_jval_destroy(&jcreate_tcp); - iotjs_jval_destroy(&jclient_tcp); + args[argc++] = jclient_tcp; + jerry_release_value(jcreate_tcp); } - iotjs_make_callback(&jonconnection, jtcp, &args); + iotjs_invoke_callback(jonconnection, jtcp, args, argc); - iotjs_jval_destroy(&jonconnection); - iotjs_jargs_destroy(&args); + jerry_release_value(jonconnection); + for (size_t i = 0; i < argc; i++) { + jerry_release_value(args[i]); + } } -JHANDLER_FUNCTION(Listen) { - JHANDLER_DECLARE_THIS_PTR(tcpwrap, tcp_wrap); - DJHANDLER_CHECK_ARGS(1, number); - - int backlog = JHANDLER_GET_ARG(0, number); +JS_FUNCTION(tcp_listen) { + JS_DECLARE_PTR(jthis, uv_tcp_t, tcp_handle); + DJS_CHECK_ARGS(1, number); - int err = uv_listen((uv_stream_t*)(iotjs_tcpwrap_tcp_handle(tcp_wrap)), - backlog, OnConnection); + int backlog = JS_GET_ARG(0, number); + int err = uv_listen((uv_stream_t*)tcp_handle, backlog, on_connection); - iotjs_jhandler_return_number(jhandler, err); + return jerry_create_number(err); } void AfterWrite(uv_write_t* req, int status) { - iotjs_write_reqwrap_t* req_wrap = (iotjs_write_reqwrap_t*)(req->data); - iotjs_tcpwrap_t* tcp_wrap = (iotjs_tcpwrap_t*)(req->handle->data); - IOTJS_ASSERT(req_wrap != NULL); - IOTJS_ASSERT(tcp_wrap != NULL); - - // Take callback function object. - const iotjs_jval_t* jcallback = iotjs_write_reqwrap_jcallback(req_wrap); - - // Only parameter is status code. - iotjs_jargs_t args = iotjs_jargs_create(1); - iotjs_jargs_append_number(&args, status); - - // Make callback. - iotjs_make_callback(jcallback, iotjs_jval_get_undefined(), &args); - - // Destroy args - iotjs_jargs_destroy(&args); - - // Release request wrapper. - iotjs_write_reqwrap_dispatched(req_wrap); + iotjs_tcp_report_req_result((uv_req_t*)req, status); } -JHANDLER_FUNCTION(Write) { - JHANDLER_DECLARE_THIS_PTR(tcpwrap, tcp_wrap); - DJHANDLER_CHECK_ARGS(2, object, function); +JS_FUNCTION(tcp_write) { + JS_DECLARE_PTR(jthis, uv_stream_t, tcp_handle); + DJS_CHECK_ARGS(2, object, function); - const iotjs_jval_t* jbuffer = JHANDLER_GET_ARG(0, object); + const jerry_value_t jbuffer = JS_GET_ARG(0, object); iotjs_bufferwrap_t* buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuffer); - char* buffer = iotjs_bufferwrap_buffer(buffer_wrap); size_t len = iotjs_bufferwrap_length(buffer_wrap); uv_buf_t buf; - buf.base = buffer; + buf.base = buffer_wrap->buffer; buf.len = len; - const iotjs_jval_t* arg1 = JHANDLER_GET_ARG(1, object); - iotjs_write_reqwrap_t* req_wrap = iotjs_write_reqwrap_create(arg1); + jerry_value_t arg1 = JS_GET_ARG(1, object); + uv_req_t* req_write = iotjs_uv_request_create(sizeof(uv_write_t), arg1, 0); - int err = uv_write(iotjs_write_reqwrap_req(req_wrap), - (uv_stream_t*)(iotjs_tcpwrap_tcp_handle(tcp_wrap)), &buf, - 1, AfterWrite); + int err = uv_write((uv_write_t*)req_write, tcp_handle, &buf, 1, AfterWrite); if (err) { - iotjs_write_reqwrap_dispatched(req_wrap); + iotjs_uv_request_destroy((uv_req_t*)req_write); } - iotjs_jhandler_return_number(jhandler, err); + return jerry_create_number(err); } -void OnAlloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { +static void on_alloc(uv_handle_t* handle, size_t suggested_size, + uv_buf_t* buf) { if (suggested_size > IOTJS_MAX_READ_BUFFER_SIZE) { suggested_size = IOTJS_MAX_READ_BUFFER_SIZE; } @@ -467,134 +256,112 @@ void OnAlloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { } -void OnRead(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { - iotjs_tcpwrap_t* tcp_wrap = iotjs_tcpwrap_from_handle((uv_tcp_t*)handle); - - // tcp handle - const iotjs_jval_t* jtcp = iotjs_tcpwrap_jobject(tcp_wrap); +static void on_read(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { + jerry_value_t jtcp = IOTJS_UV_HANDLE_DATA(handle)->jobject; // socket object - iotjs_jval_t jsocket = + jerry_value_t jsocket = iotjs_jval_get_property(jtcp, IOTJS_MAGIC_STRING_OWNER); - IOTJS_ASSERT(iotjs_jval_is_object(&jsocket)); + IOTJS_ASSERT(jerry_value_is_object(jsocket)); // onread callback - iotjs_jval_t jonread = + jerry_value_t jonread = iotjs_jval_get_property(jtcp, IOTJS_MAGIC_STRING_ONREAD); - IOTJS_ASSERT(iotjs_jval_is_function(&jonread)); + IOTJS_ASSERT(jerry_value_is_function(jonread)); - iotjs_jargs_t jargs = iotjs_jargs_create(4); - iotjs_jargs_append_jval(&jargs, &jsocket); - iotjs_jargs_append_number(&jargs, nread); - iotjs_jargs_append_bool(&jargs, false); + size_t argc = 3; + jerry_value_t jargs[4] = { jsocket, jerry_create_number(nread), + jerry_create_boolean(false), 0 }; if (nread <= 0) { - if (buf->base != NULL) { - iotjs_buffer_release(buf->base); - } + iotjs_buffer_release(buf->base); + if (nread < 0) { if (nread == UV__EOF) { - iotjs_jargs_replace(&jargs, 2, iotjs_jval_get_boolean(true)); + jargs[2] = jerry_create_boolean(true); } - iotjs_make_callback(&jonread, iotjs_jval_get_undefined(), &jargs); + iotjs_invoke_callback(jonread, jerry_create_undefined(), jargs, argc); } } else { - iotjs_jval_t jbuffer = iotjs_bufferwrap_create_buffer((size_t)nread); - iotjs_bufferwrap_t* buffer_wrap = iotjs_bufferwrap_from_jbuffer(&jbuffer); + jerry_value_t jbuffer = iotjs_bufferwrap_create_buffer((size_t)nread); + iotjs_bufferwrap_t* buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuffer); iotjs_bufferwrap_copy(buffer_wrap, buf->base, (size_t)nread); - iotjs_jargs_append_jval(&jargs, &jbuffer); - iotjs_make_callback(&jonread, iotjs_jval_get_undefined(), &jargs); + jargs[argc++] = jbuffer; + iotjs_invoke_callback(jonread, jerry_create_undefined(), jargs, argc); - iotjs_jval_destroy(&jbuffer); iotjs_buffer_release(buf->base); } - iotjs_jargs_destroy(&jargs); - iotjs_jval_destroy(&jonread); - iotjs_jval_destroy(&jsocket); + for (uint8_t i = 0; i < argc; i++) { + jerry_release_value(jargs[i]); + } + jerry_release_value(jonread); } -JHANDLER_FUNCTION(ReadStart) { - JHANDLER_DECLARE_THIS_PTR(tcpwrap, tcp_wrap); +JS_FUNCTION(tcp_read_start) { + JS_DECLARE_PTR(jthis, uv_stream_t, tcp_handle); - int err = uv_read_start((uv_stream_t*)(iotjs_tcpwrap_tcp_handle(tcp_wrap)), - OnAlloc, OnRead); + int err = uv_read_start(tcp_handle, on_alloc, on_read); - iotjs_jhandler_return_number(jhandler, err); + return jerry_create_number(err); } static void AfterShutdown(uv_shutdown_t* req, int status) { - iotjs_shutdown_reqwrap_t* req_wrap = (iotjs_shutdown_reqwrap_t*)(req->data); - iotjs_tcpwrap_t* tcp_wrap = (iotjs_tcpwrap_t*)(req->handle->data); - IOTJS_ASSERT(req_wrap != NULL); - IOTJS_ASSERT(tcp_wrap != NULL); - - // function onShutdown(status) - const iotjs_jval_t* jonshutdown = iotjs_shutdown_reqwrap_jcallback(req_wrap); - IOTJS_ASSERT(iotjs_jval_is_function(jonshutdown)); - - iotjs_jargs_t args = iotjs_jargs_create(1); - iotjs_jargs_append_number(&args, status); - - iotjs_make_callback(jonshutdown, iotjs_jval_get_undefined(), &args); - - iotjs_jargs_destroy(&args); - - iotjs_shutdown_reqwrap_dispatched(req_wrap); + iotjs_tcp_report_req_result((uv_req_t*)req, status); } -JHANDLER_FUNCTION(Shutdown) { - JHANDLER_DECLARE_THIS_PTR(tcpwrap, tcp_wrap); +JS_FUNCTION(tcp_shutdown) { + JS_DECLARE_PTR(jthis, uv_stream_t, tcp_handle); - DJHANDLER_CHECK_ARGS(1, function); + DJS_CHECK_ARGS(1, function); - const iotjs_jval_t* arg0 = JHANDLER_GET_ARG(0, object); - iotjs_shutdown_reqwrap_t* req_wrap = iotjs_shutdown_reqwrap_create(arg0); + jerry_value_t arg0 = JS_GET_ARG(0, object); + uv_shutdown_t* req_shutdown = + (uv_shutdown_t*)iotjs_uv_request_create(sizeof(uv_shutdown_t), arg0, 0); - int err = uv_shutdown(iotjs_shutdown_reqwrap_req(req_wrap), - (uv_stream_t*)(iotjs_tcpwrap_tcp_handle(tcp_wrap)), - AfterShutdown); + int err = uv_shutdown(req_shutdown, tcp_handle, AfterShutdown); if (err) { - iotjs_shutdown_reqwrap_dispatched(req_wrap); + iotjs_uv_request_destroy((uv_req_t*)req_shutdown); } - iotjs_jhandler_return_number(jhandler, err); + return jerry_create_number(err); } // Enable/Disable keepalive option. // [0] enable // [1] delay -JHANDLER_FUNCTION(SetKeepAlive) { - JHANDLER_DECLARE_THIS_PTR(tcpwrap, tcp_wrap); +JS_FUNCTION(tcp_set_keep_alive) { + JS_DECLARE_PTR(jthis, uv_tcp_t, tcp_handle); - DJHANDLER_CHECK_ARGS(2, number, number); + DJS_CHECK_ARGS(2, number, number); - int enable = JHANDLER_GET_ARG(0, number); - unsigned delay = JHANDLER_GET_ARG(1, number); + int enable = JS_GET_ARG(0, number); + unsigned delay = JS_GET_ARG(1, number); - int err = uv_tcp_keepalive(iotjs_tcpwrap_tcp_handle(tcp_wrap), enable, delay); + int err = uv_tcp_keepalive(tcp_handle, enable, delay); - iotjs_jhandler_return_number(jhandler, err); + return jerry_create_number(err); } -JHANDLER_FUNCTION(ErrName) { - DJHANDLER_CHECK_THIS(object); - DJHANDLER_CHECK_ARGS(1, number); +JS_FUNCTION(tcp_err_name) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(1, number); - int errorcode = JHANDLER_GET_ARG(0, number); - iotjs_jhandler_return_string_raw(jhandler, uv_err_name(errorcode)); + int errorcode = JS_GET_ARG(0, number); + return jerry_create_string_from_utf8( + (const jerry_char_t*)uv_err_name(errorcode)); } // used in iotjs_module_udp.cpp -void AddressToJS(const iotjs_jval_t* obj, const sockaddr* addr) { +void address_to_js(jerry_value_t obj, const sockaddr* addr) { char ip[INET6_ADDRSTRLEN]; const sockaddr_in* a4; const sockaddr_in6* a6; @@ -630,37 +397,43 @@ void AddressToJS(const iotjs_jval_t* obj, const sockaddr* addr) { } } -GetSockNameFunction(tcpwrap, tcp_handle, uv_tcp_getsockname); +JS_FUNCTION(tcp_get_socket_name) { + JS_DECLARE_PTR(jthis, uv_tcp_t, tcp_handle); -JHANDLER_FUNCTION(GetSockeName) { - DoGetSockName(jhandler); + DJS_CHECK_ARGS(1, object); + + sockaddr_storage storage; + int addrlen = sizeof(storage); + sockaddr* const addr = (sockaddr*)(&storage); + int err = uv_tcp_getsockname(tcp_handle, addr, &addrlen); + if (err == 0) + address_to_js(JS_GET_ARG(0, object), addr); + return jerry_create_number(err); } -iotjs_jval_t InitTcp() { - iotjs_jval_t tcp = iotjs_jval_create_function_with_dispatch(TCP); - - iotjs_jval_t prototype = iotjs_jval_create_object(); - iotjs_jval_t errname = iotjs_jval_create_function_with_dispatch(ErrName); - - iotjs_jval_set_property_jval(&tcp, IOTJS_MAGIC_STRING_PROTOTYPE, &prototype); - iotjs_jval_set_property_jval(&tcp, IOTJS_MAGIC_STRING_ERRNAME, &errname); - - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_OPEN, Open); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_CLOSE, Close); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_CONNECT, Connect); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_BIND, Bind); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_LISTEN, Listen); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_WRITE, Write); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_READSTART, ReadStart); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_SHUTDOWN, Shutdown); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_SETKEEPALIVE, - SetKeepAlive); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_GETSOCKNAME, - GetSockeName); - - iotjs_jval_destroy(&prototype); - iotjs_jval_destroy(&errname); +jerry_value_t iotjs_init_tcp(void) { + jerry_value_t tcp = jerry_create_external_function(tcp_constructor); + + jerry_value_t prototype = jerry_create_object(); + + iotjs_jval_set_property_jval(tcp, IOTJS_MAGIC_STRING_PROTOTYPE, prototype); + iotjs_jval_set_method(tcp, IOTJS_MAGIC_STRING_ERRNAME, tcp_err_name); + + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_CLOSE, tcp_close); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_CONNECT, tcp_connect); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_BIND, tcp_bind); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_LISTEN, tcp_listen); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_WRITE, tcp_write); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_READSTART, + tcp_read_start); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_SHUTDOWN, tcp_shutdown); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_SETKEEPALIVE, + tcp_set_keep_alive); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_GETSOCKNAME, + tcp_get_socket_name); + + jerry_release_value(prototype); return tcp; } diff --git a/src/modules/iotjs_module_tcp.h b/src/modules/iotjs_module_tcp.h index 156bf89020..c67e751ef4 100644 --- a/src/modules/iotjs_module_tcp.h +++ b/src/modules/iotjs_module_tcp.h @@ -19,8 +19,6 @@ #include "iotjs_binding.h" -#include "iotjs_handlewrap.h" -#include "iotjs_reqwrap.h" typedef struct sockaddr sockaddr; @@ -29,82 +27,7 @@ typedef struct sockaddr_in6 sockaddr_in6; typedef struct sockaddr_storage sockaddr_storage; -typedef struct { - iotjs_handlewrap_t handlewrap; - uv_tcp_t handle; -} IOTJS_VALIDATED_STRUCT(iotjs_tcpwrap_t); - - -iotjs_tcpwrap_t* iotjs_tcpwrap_create(const iotjs_jval_t* jtcp); - -iotjs_tcpwrap_t* iotjs_tcpwrap_from_handle(uv_tcp_t* handle); -iotjs_tcpwrap_t* iotjs_tcpwrap_from_jobject(const iotjs_jval_t* jtcp); - -uv_tcp_t* iotjs_tcpwrap_tcp_handle(iotjs_tcpwrap_t* tcpwrap); -iotjs_jval_t* iotjs_tcpwrap_jobject(iotjs_tcpwrap_t* tcpwrap); - - -typedef struct { - iotjs_reqwrap_t reqwrap; - uv_connect_t req; -} IOTJS_VALIDATED_STRUCT(iotjs_connect_reqwrap_t); - -#define THIS iotjs_connect_reqwrap_t* connect_reqwrap -iotjs_connect_reqwrap_t* iotjs_connect_reqwrap_create( - const iotjs_jval_t* jcallback); -void iotjs_connect_reqwrap_dispatched(THIS); -uv_connect_t* iotjs_connect_reqwrap_req(THIS); -const iotjs_jval_t* iotjs_connect_reqwrap_jcallback(THIS); -#undef THIS - - -typedef struct { - iotjs_reqwrap_t reqwrap; - uv_write_t req; -} IOTJS_VALIDATED_STRUCT(iotjs_write_reqwrap_t); - -#define THIS iotjs_write_reqwrap_t* write_reqwrap -iotjs_write_reqwrap_t* iotjs_write_reqwrap_create( - const iotjs_jval_t* jcallback); -void iotjs_write_reqwrap_dispatched(THIS); -uv_write_t* iotjs_write_reqwrap_req(THIS); -const iotjs_jval_t* iotjs_write_reqwrap_jcallback(THIS); -#undef THIS - - -typedef struct { - iotjs_reqwrap_t reqwrap; - uv_shutdown_t req; -} IOTJS_VALIDATED_STRUCT(iotjs_shutdown_reqwrap_t); - -#define THIS iotjs_shutdown_reqwrap_t* shutdown_reqwrap -iotjs_shutdown_reqwrap_t* iotjs_shutdown_reqwrap_create( - const iotjs_jval_t* jcallback); -void iotjs_shutdown_reqwrap_dispatched(THIS); -uv_shutdown_t* iotjs_shutdown_reqwrap_req(THIS); -const iotjs_jval_t* iotjs_shutdown_reqwrap_jcallback(THIS); -#undef THIS - - -void AddressToJS(const iotjs_jval_t* obj, const sockaddr* addr); - - -#define GetSockNameFunction(wraptype, handletype, function) \ - static void DoGetSockName(iotjs_jhandler_t* jhandler) { \ - DJHANDLER_CHECK_ARGS(1, object); \ - \ - iotjs_##wraptype##_t* wrap = \ - iotjs_##wraptype##_from_jobject(JHANDLER_GET_THIS(object)); \ - IOTJS_ASSERT(wrap != NULL); \ - \ - sockaddr_storage storage; \ - int addrlen = sizeof(storage); \ - sockaddr* const addr = (sockaddr*)(&storage); \ - int err = function(iotjs_##wraptype##_##handletype(wrap), addr, &addrlen); \ - if (err == 0) \ - AddressToJS(JHANDLER_GET_ARG(0, object), addr); \ - iotjs_jhandler_return_number(jhandler, err); \ - } +void address_to_js(jerry_value_t obj, const sockaddr* addr); #endif /* IOTJS_MODULE_TCP_H */ diff --git a/src/modules/iotjs_module_testdriver.c b/src/modules/iotjs_module_testdriver.c deleted file mode 100644 index 2e8a7220fe..0000000000 --- a/src/modules/iotjs_module_testdriver.c +++ /dev/null @@ -1,71 +0,0 @@ -/* Copyright 2016-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_def.h" -#include "iotjs_module_timer.h" - - -// Only for test driver -JHANDLER_FUNCTION(IsAliveExceptFor) { - JHANDLER_CHECK(iotjs_jhandler_get_arg_length(jhandler) == 1); - const iotjs_environment_t* env = iotjs_environment_get(); - uv_loop_t* loop = iotjs_environment_loop(env); - - const iotjs_jval_t* arg0 = iotjs_jhandler_get_arg(jhandler, 0); - - if (iotjs_jval_is_null(arg0)) { - int alive = uv_loop_alive(loop); - - iotjs_jhandler_return_boolean(jhandler, alive); - } else { - JHANDLER_CHECK(iotjs_jval_is_object(arg0)); - - iotjs_jval_t jtimer = - iotjs_jval_get_property(arg0, IOTJS_MAGIC_STRING_HANDLER); - - iotjs_timerwrap_t* timer_wrap = iotjs_timerwrap_from_jobject(&jtimer); - iotjs_jval_destroy(&jtimer); - - bool has_active_reqs = uv_loop_has_active_reqs(loop); - bool has_closing_handler = loop->closing_handles != NULL; - - bool ret = true; - bool alive = !has_active_reqs && !has_closing_handler; - if (alive) { - unsigned int active_handlers = loop->active_handles; - if (active_handlers == 1u) { - const uv_timer_t* timer_handle = iotjs_timerwrap_handle(timer_wrap); - int timer_alive = uv_is_active((uv_handle_t*)timer_handle); - - if (timer_alive) { - // If the timer handler we set for test driver is alive, - // then it can be safely terminated. - ret = false; - } - } - } - - iotjs_jhandler_return_boolean(jhandler, ret); - } -} - - -iotjs_jval_t InitTestdriver() { - iotjs_jval_t testdriver = iotjs_jval_create_object(); - iotjs_jval_set_method(&testdriver, IOTJS_MAGIC_STRING_ISALIVEEXCEPTFOR, - IsAliveExceptFor); - - return testdriver; -} diff --git a/src/modules/iotjs_module_timer.c b/src/modules/iotjs_module_timer.c index c08b108628..5c86d7f788 100644 --- a/src/modules/iotjs_module_timer.c +++ b/src/modules/iotjs_module_timer.c @@ -14,162 +14,80 @@ */ #include "iotjs_def.h" -#include "iotjs_module_timer.h" +#include "iotjs_uv_handle.h" -static void iotjs_timerwrap_destroy(iotjs_timerwrap_t* timerwrap); -static void iotjs_timerwrap_on_timeout(iotjs_timerwrap_t* timerwrap); -IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(timerwrap); +static const jerry_object_native_info_t this_module_native_info = { NULL }; -iotjs_timerwrap_t* iotjs_timerwrap_create(const iotjs_jval_t* jtimer) { - iotjs_timerwrap_t* timerwrap = IOTJS_ALLOC(iotjs_timerwrap_t); - uv_timer_t* uv_timer = IOTJS_ALLOC(uv_timer_t); - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_timerwrap_t, timerwrap); +void iotjs_timer_object_init(jerry_value_t jtimer) { + uv_handle_t* handle = iotjs_uv_handle_create(sizeof(uv_timer_t), jtimer, + &this_module_native_info, 0); - iotjs_handlewrap_initialize(&_this->handlewrap, jtimer, - (uv_handle_t*)(uv_timer), - &this_module_native_info); - - // Initialize timer handler. const iotjs_environment_t* env = iotjs_environment_get(); - uv_timer_init(iotjs_environment_loop(env), uv_timer); - - return timerwrap; -} - - -static void iotjs_timerwrap_destroy(iotjs_timerwrap_t* timerwrap) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_timerwrap_t, timerwrap); - iotjs_handlewrap_destroy(&_this->handlewrap); - - IOTJS_RELEASE(timerwrap); -} - -static void TimoutHandlerDestroy(uv_handle_t* handle) { - IOTJS_RELEASE(handle); -} - -// This function is called from uv when timeout expires. -static void TimeoutHandler(uv_timer_t* handle) { - // Find timer wrap from handle. - iotjs_timerwrap_t* timer_wrap = iotjs_timerwrap_from_handle(handle); - - // Call the timeout handler. - iotjs_timerwrap_on_timeout(timer_wrap); + uv_timer_init(iotjs_environment_loop(env), (uv_timer_t*)handle); } -int iotjs_timerwrap_start(iotjs_timerwrap_t* timerwrap, uint64_t timeout, - uint64_t repeat) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_timerwrap_t, timerwrap); - - // Start uv timer. - uv_timer_t* uv_timer = - (uv_timer_t*)iotjs_handlewrap_get_uv_handle(&_this->handlewrap); - return uv_timer_start(uv_timer, TimeoutHandler, timeout, repeat); -} - +static void timeout_handler(uv_timer_t* handle) { + IOTJS_ASSERT(handle != NULL); -int iotjs_timerwrap_stop(iotjs_timerwrap_t* timerwrap) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_timerwrap_t, timerwrap); - - if (!uv_is_closing(iotjs_handlewrap_get_uv_handle(&_this->handlewrap))) { - iotjs_handlewrap_close(&_this->handlewrap, TimoutHandlerDestroy); - } - - return 0; -} - - -static void iotjs_timerwrap_on_timeout(iotjs_timerwrap_t* timerwrap) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_timerwrap_t, timerwrap); - - // Call javascript timeout handler function. - const iotjs_jval_t* jobject = iotjs_timerwrap_jobject(timerwrap); - iotjs_jval_t jcallback = + jerry_value_t jobject = IOTJS_UV_HANDLE_DATA(handle)->jobject; + jerry_value_t jcallback = iotjs_jval_get_property(jobject, IOTJS_MAGIC_STRING_HANDLETIMEOUT); - iotjs_make_callback(&jcallback, jobject, iotjs_jargs_get_empty()); - iotjs_jval_destroy(&jcallback); -} - - -uv_timer_t* iotjs_timerwrap_handle(iotjs_timerwrap_t* timerwrap) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_timerwrap_t, timerwrap); - return (uv_timer_t*)iotjs_handlewrap_get_uv_handle(&_this->handlewrap); -} - - -iotjs_jval_t* iotjs_timerwrap_jobject(iotjs_timerwrap_t* timerwrap) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_timerwrap_t, timerwrap); - iotjs_jval_t* jobject = iotjs_handlewrap_jobject(&_this->handlewrap); - IOTJS_ASSERT(iotjs_jval_is_object(jobject)); - return jobject; + iotjs_invoke_callback(jcallback, jobject, NULL, 0); + jerry_release_value(jcallback); } -iotjs_timerwrap_t* iotjs_timerwrap_from_handle(uv_timer_t* timer_handle) { - uv_handle_t* handle = (uv_handle_t*)(timer_handle); - iotjs_handlewrap_t* handlewrap = iotjs_handlewrap_from_handle(handle); - iotjs_timerwrap_t* timerwrap = (iotjs_timerwrap_t*)handlewrap; - IOTJS_ASSERT(iotjs_timerwrap_handle(timerwrap) == timer_handle); - return timerwrap; -} - - -iotjs_timerwrap_t* iotjs_timerwrap_from_jobject(const iotjs_jval_t* jtimer) { - iotjs_handlewrap_t* handlewrap = iotjs_handlewrap_from_jobject(jtimer); - return (iotjs_timerwrap_t*)handlewrap; -} - - -JHANDLER_FUNCTION(Start) { +JS_FUNCTION(timer_start) { // Check parameters. - JHANDLER_DECLARE_THIS_PTR(timerwrap, timer_wrap); - JHANDLER_CHECK_ARGS(2, number, number); + JS_DECLARE_PTR(jthis, uv_timer_t, timer_handle); + DJS_CHECK_ARGS(2, number, number); // parameters. - uint64_t timeout = JHANDLER_GET_ARG(0, number); - uint64_t repeat = JHANDLER_GET_ARG(1, number); + uint64_t timeout = JS_GET_ARG(0, number); + uint64_t repeat = JS_GET_ARG(1, number); // Start timer. - int res = iotjs_timerwrap_start(timer_wrap, timeout, repeat); + int res = uv_timer_start(timer_handle, timeout_handler, timeout, repeat); - iotjs_jhandler_return_number(jhandler, res); + return jerry_create_number(res); } -JHANDLER_FUNCTION(Stop) { - JHANDLER_DECLARE_THIS_PTR(timerwrap, timer_wrap); +JS_FUNCTION(timer_stop) { + JS_DECLARE_PTR(jthis, uv_handle_t, timer_handle); // Stop timer. - int res = iotjs_timerwrap_stop(timer_wrap); - iotjs_jhandler_return_number(jhandler, res); + if (!uv_is_closing(timer_handle)) { + iotjs_uv_handle_close(timer_handle, NULL); + } + + return jerry_create_number(0); } -JHANDLER_FUNCTION(Timer) { - JHANDLER_CHECK_THIS(object); +JS_FUNCTION(timer_constructor) { + DJS_CHECK_THIS(); - const iotjs_jval_t* jtimer = JHANDLER_GET_THIS(object); + const jerry_value_t jtimer = JS_GET_THIS(); - iotjs_timerwrap_t* timer_wrap = iotjs_timerwrap_create(jtimer); - IOTJS_ASSERT(iotjs_jval_is_object(iotjs_timerwrap_jobject(timer_wrap))); - IOTJS_ASSERT(iotjs_jval_get_object_native_handle(jtimer) != 0); + iotjs_timer_object_init(jtimer); + return jerry_create_undefined(); } -iotjs_jval_t InitTimer() { - iotjs_jval_t timer = iotjs_jval_create_function_with_dispatch(Timer); +jerry_value_t iotjs_init_timer(void) { + jerry_value_t timer = jerry_create_external_function(timer_constructor); - iotjs_jval_t prototype = iotjs_jval_create_object(); - iotjs_jval_set_property_jval(&timer, IOTJS_MAGIC_STRING_PROTOTYPE, - &prototype); + jerry_value_t prototype = jerry_create_object(); + iotjs_jval_set_property_jval(timer, IOTJS_MAGIC_STRING_PROTOTYPE, prototype); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_START, Start); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_STOP, Stop); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_START, timer_start); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_STOP, timer_stop); - iotjs_jval_destroy(&prototype); + jerry_release_value(prototype); return timer; } diff --git a/src/modules/iotjs_module_timer.h b/src/modules/iotjs_module_timer.h deleted file mode 100644 index de03875af6..0000000000 --- a/src/modules/iotjs_module_timer.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright 2015-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_TIMER_H -#define IOTJS_MODULE_TIMER_H - - -#include "iotjs_binding.h" -#include "iotjs_handlewrap.h" - - -typedef struct { - iotjs_handlewrap_t handlewrap; -} IOTJS_VALIDATED_STRUCT(iotjs_timerwrap_t); - - -iotjs_timerwrap_t* iotjs_timerwrap_create(const iotjs_jval_t* jtimer); - -iotjs_timerwrap_t* iotjs_timerwrap_from_jobject(const iotjs_jval_t* jtimer); -iotjs_timerwrap_t* iotjs_timerwrap_from_handle(uv_timer_t* timer_handle); - -uv_timer_t* iotjs_timerwrap_handle(iotjs_timerwrap_t* timerwrap); -iotjs_jval_t* iotjs_timerwrap_jobject(iotjs_timerwrap_t* timerwrap); - -// Start timer. -int iotjs_timerwrap_start(iotjs_timerwrap_t* timerwrap, uint64_t timeout, - uint64_t repeat); -// Stop & close timer. -int iotjs_timerwrap_stop(iotjs_timerwrap_t* timerwrap); - - -#endif /* IOTJS_MODULE_TIMER_H */ diff --git a/src/modules/iotjs_module_fs.h b/src/modules/iotjs_module_tizen.c similarity index 50% rename from src/modules/iotjs_module_fs.h rename to src/modules/iotjs_module_tizen.c index aaab3797bf..7f8d1fcac1 100644 --- a/src/modules/iotjs_module_fs.h +++ b/src/modules/iotjs_module_tizen.c @@ -1,4 +1,4 @@ -/* Copyright 2015-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. @@ -13,27 +13,21 @@ * limitations under the License. */ - -#ifndef IOTJS_MODULE_FS_H -#define IOTJS_MODULE_FS_H - - #include "iotjs_def.h" -#include "iotjs_reqwrap.h" - - -typedef struct { - iotjs_reqwrap_t reqwrap; - uv_fs_t req; -} IOTJS_VALIDATED_STRUCT(iotjs_fs_reqwrap_t); +#include "iotjs_module_bridge.h" +extern void iotjs_tizen_func(const char* command, const char* message, + void* handle); -iotjs_fs_reqwrap_t* iotjs_fs_reqwrap_create(const iotjs_jval_t* jcallback); - -void iotjs_fs_reqwrap_dispatched(iotjs_fs_reqwrap_t* fs_reqwrap); - -uv_fs_t* iotjs_fs_reqwrap_req(iotjs_fs_reqwrap_t* fs_reqwrap); -const iotjs_jval_t* iotjs_fs_reqwrap_jcallback(iotjs_fs_reqwrap_t* fs_reqwrap); - - -#endif /* IOTJS_MODULE_FS_H */ +/** + * Init method called by IoT.js + */ +jerry_value_t iotjs_init_tizen() { + char* module_name = IOTJS_MAGIC_STRING_TIZEN; + jerry_value_t mymodule = jerry_create_object(); + iotjs_jval_set_property_string_raw(mymodule, IOTJS_MAGIC_STRING_MODULE_NAME, + module_name); + + iotjs_bridge_register(module_name, iotjs_tizen_func); + return mymodule; +} diff --git a/src/modules/iotjs_module_tls.c b/src/modules/iotjs_module_tls.c new file mode 100644 index 0000000000..a6a95f11be --- /dev/null +++ b/src/modules/iotjs_module_tls.c @@ -0,0 +1,636 @@ +/* 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_module_tls.h" +#include "iotjs_module_buffer.h" + +#include "stdarg.h" + +static void iotjs_tls_context_destroy(iotjs_tls_context_t *tls_context); + +static const jerry_object_native_info_t tls_context_native_info = { + .free_cb = (jerry_object_native_free_callback_t)iotjs_tls_context_destroy +}; + + +static void iotjs_tls_context_destroy(iotjs_tls_context_t *tls_context) { + if (tls_context->ref_count > 1) { + tls_context->ref_count--; + return; + } + + mbedtls_x509_crt_free(&tls_context->cert_auth); + mbedtls_x509_crt_free(&tls_context->own_cert); + mbedtls_pk_free(&tls_context->pkey); + mbedtls_ctr_drbg_free(&tls_context->ctr_drbg); + mbedtls_entropy_free(&tls_context->entropy); + + IOTJS_RELEASE(tls_context); +} + + +static iotjs_tls_context_t *iotjs_tls_context_create( + const jerry_value_t jobject) { + iotjs_tls_context_t *tls_context = IOTJS_ALLOC(iotjs_tls_context_t); + + tls_context->ref_count = 1; + tls_context->context_flags = 0; + mbedtls_entropy_init(&tls_context->entropy); + mbedtls_ctr_drbg_init(&tls_context->ctr_drbg); + mbedtls_pk_init(&tls_context->pkey); + mbedtls_x509_crt_init(&tls_context->own_cert); + mbedtls_x509_crt_init(&tls_context->cert_auth); + + jerry_set_object_native_pointer(jobject, tls_context, + &tls_context_native_info); + + return tls_context; +} + + +IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(tls); + + +static void iotjs_tls_destroy(iotjs_tls_t *tls_data) { + mbedtls_ssl_free(&tls_data->ssl); + mbedtls_ssl_config_free(&tls_data->conf); + iotjs_tls_context_destroy(tls_data->tls_context); + + IOTJS_RELEASE(tls_data->bio.receive_bio.mem); + IOTJS_RELEASE(tls_data->bio.send_bio.mem); + + IOTJS_RELEASE(tls_data); +} + + +static iotjs_tls_t *iotjs_tls_create(const jerry_value_t jobject, + iotjs_tls_context_t *tls_context) { + iotjs_tls_t *tls_data = IOTJS_ALLOC(iotjs_tls_t); + + tls_context->ref_count++; + + tls_data->tls_context = tls_context; + mbedtls_ssl_config_init(&tls_data->conf); + mbedtls_ssl_init(&tls_data->ssl); + tls_data->state = TLS_HANDSHAKE_READY; + + tls_data->jobject = jobject; + jerry_set_object_native_pointer(jobject, tls_data, &this_module_native_info); + + return tls_data; +} + + +static void iotjs_bio_init(iotjs_bio_t *bio, size_t size) { + bio->mem = (char *)iotjs_buffer_allocate(size); + bio->size = size; + bio->read_index = 0; + bio->write_index = 0; +} + + +static size_t iotjs_bio_pending(iotjs_bio_t *bio) { + if (bio->read_index <= bio->write_index) { + return bio->write_index - bio->read_index; + } + + return bio->write_index + bio->size - bio->read_index; +} + + +static size_t iotjs_bio_remaining(iotjs_bio_t *bio) { + if (bio->write_index < bio->read_index) { + return bio->read_index - bio->write_index - 1; + } + + return bio->read_index + bio->size - bio->write_index - 1; +} + + +static void iotjs_bio_read(iotjs_bio_t *bio, char *buf, size_t size) { + IOTJS_ASSERT(size <= iotjs_bio_pending(bio)); + + if (bio->read_index + size > bio->size) { + size_t copy_size = bio->size - bio->read_index; + + memcpy(buf, bio->mem + bio->read_index, copy_size); + size -= copy_size; + buf += copy_size; + bio->read_index = 0; + } + + memcpy(buf, bio->mem + bio->read_index, size); + bio->read_index += size; +} + + +static void iotjs_bio_write(iotjs_bio_t *bio, const char *buf, size_t size) { + IOTJS_ASSERT(size <= iotjs_bio_remaining(bio)); + + if (bio->write_index + size > bio->size) { + size_t copy_size = bio->size - bio->write_index; + + memcpy(bio->mem + bio->write_index, buf, copy_size); + size -= copy_size; + buf += copy_size; + bio->write_index = 0; + } + + memcpy(bio->mem + bio->write_index, buf, size); + bio->write_index += size; +} + + +static int iotjs_bio_net_send(void *ctx, const unsigned char *buf, size_t len) { + iotjs_bio_t *send_bio = &(((iotjs_bio_pair_t *)ctx)->send_bio); + + size_t remaining = iotjs_bio_remaining(send_bio); + + if (remaining == 0) { + return MBEDTLS_ERR_SSL_WANT_WRITE; + } + + if (len > remaining) { + len = remaining; + } + + iotjs_bio_write(send_bio, (const char *)buf, len); + return (int)len; +} + +static int iotjs_bio_net_receive(void *ctx, unsigned char *buf, size_t len) { + iotjs_bio_t *receive_bio = &(((iotjs_bio_pair_t *)ctx)->receive_bio); + + size_t pending = iotjs_bio_pending(receive_bio); + + if (pending == 0) { + return MBEDTLS_ERR_SSL_WANT_READ; + } + + if (len > pending) { + len = pending; + } + + iotjs_bio_read(receive_bio, (char *)buf, len); + return (int)len; +} + + +JS_FUNCTION(tls_tlscontext) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(1, object); + + jerry_value_t jtls = JS_GET_THIS(); + iotjs_tls_context_t *tls_context = iotjs_tls_context_create(jtls); + + jerry_value_t joptions = JS_GET_ARG(0, object); + + // Set deterministic random bit generator + if (mbedtls_ctr_drbg_seed(&tls_context->ctr_drbg, mbedtls_entropy_func, + &tls_context->entropy, NULL, 0) != 0) { + return JS_CREATE_ERROR(COMMON, "drbg seeding failed"); + } + + // User provided certificate + int ret = 0; + + jerry_value_t jcert = + iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_CERT); + jerry_value_t jkey = + iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_KEY); + + iotjs_string_t cert_string; + iotjs_string_t key_string; + + if (iotjs_jbuffer_as_string(jcert, &cert_string)) { + const char *cert_chars = iotjs_string_data(&cert_string); + + ret = mbedtls_x509_crt_parse(&tls_context->own_cert, + (const unsigned char *)cert_chars, + (size_t)iotjs_string_size(&cert_string) + 1); + + iotjs_string_destroy(&cert_string); + + if (ret == 0 && iotjs_jbuffer_as_string(jkey, &key_string)) { + const char *key_chars = iotjs_string_data(&key_string); + + ret = mbedtls_pk_parse_key(&tls_context->pkey, + (const unsigned char *)key_chars, + (size_t)iotjs_string_size(&key_string) + 1, + NULL, 0); + + iotjs_string_destroy(&key_string); + + if (ret == 0) { + // Both own_cert and pkey must be valid for setting this flag. + tls_context->context_flags |= SSL_CONTEXT_HAS_KEY; + } + } else { + ret = -1; + } + } else if (!jerry_value_is_undefined(jcert) || + !jerry_value_is_undefined(jkey)) { + ret = -1; + } + + jerry_release_value(jcert); + jerry_release_value(jkey); + + if (ret != 0) { + return JS_CREATE_ERROR(COMMON, "key or certificate parsing failed"); + } + + // User provided trusted certificates + jerry_value_t jcert_auth = + iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_CA); + iotjs_string_t cert_auth_string; + + if (iotjs_jbuffer_as_string(jcert_auth, &cert_auth_string)) { + const char *cert_auth_chars = iotjs_string_data(&cert_auth_string); + + ret = mbedtls_x509_crt_parse(&tls_context->cert_auth, + (const unsigned char *)cert_auth_chars, + (size_t)iotjs_string_size(&cert_auth_string) + + 1); + + iotjs_string_destroy(&cert_auth_string); + } else if (!jerry_value_is_undefined(jcert_auth)) { + ret = -1; + } else { + // Parse the default certificate authority + ret = mbedtls_x509_crt_parse(&tls_context->cert_auth, + (const unsigned char *)SSL_CA_PEM, + sizeof(SSL_CA_PEM)); + } + + jerry_release_value(jcert_auth); + + if (ret) { + return JS_CREATE_ERROR(COMMON, "certificate authority (CA) parsing failed"); + } + + return jerry_create_undefined(); +} + + +JS_FUNCTION(tls_init) { + DJS_CHECK_ARGS(3, object, object, object); + + jerry_value_t jtls_socket = JS_GET_ARG(0, object); + jerry_value_t joptions = JS_GET_ARG(1, object); + + // Get context + jerry_value_t jtls_context = JS_GET_ARG(2, object); + iotjs_tls_context_t *tls_context = NULL; + if (!jerry_get_object_native_pointer(jtls_context, (void **)&tls_context, + &tls_context_native_info)) { + return JS_CREATE_ERROR(COMMON, "secure context not available"); + } + + iotjs_tls_t *tls_data = iotjs_tls_create(jtls_socket, tls_context); + + // Check server + jerry_value_t jis_server = + iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_ISSERVER); + bool is_server = jerry_value_to_boolean(jis_server); + jerry_release_value(jis_server); + + if (tls_context->context_flags & SSL_CONTEXT_HAS_KEY) { + if (mbedtls_ssl_conf_own_cert(&tls_data->conf, &tls_context->own_cert, + &tls_context->pkey) != 0) { + return JS_CREATE_ERROR(COMMON, "certificate/private key cannot be set"); + } + } + + mbedtls_ssl_conf_ca_chain(&tls_data->conf, &tls_context->cert_auth, NULL); + + mbedtls_ssl_conf_rng(&tls_data->conf, mbedtls_ctr_drbg_random, + &tls_context->ctr_drbg); + + int endpoint = is_server ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT; + + if (mbedtls_ssl_config_defaults(&tls_data->conf, endpoint, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT)) { + return JS_CREATE_ERROR(COMMON, "SSL Configuration failed"); + } + + // if true, verifies CAs, must emit error if fails + int auth_mode = + is_server ? MBEDTLS_SSL_VERIFY_NONE : MBEDTLS_SSL_VERIFY_REQUIRED; + + jerry_value_t jauth_mode = + iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_REJECTUNAUTHORIZED); + + if (!jerry_value_is_undefined(jauth_mode)) { + if (jerry_value_to_boolean(jauth_mode)) { + auth_mode = MBEDTLS_SSL_VERIFY_REQUIRED; + } else { + auth_mode = MBEDTLS_SSL_VERIFY_OPTIONAL; + } + } + + jerry_release_value(jauth_mode); + + mbedtls_ssl_conf_authmode(&tls_data->conf, auth_mode); + + if (mbedtls_ssl_setup(&tls_data->ssl, &tls_data->conf)) { + return JS_CREATE_ERROR(COMMON, "SSL setup failed"); + } + + // Connect mbedtls with iotjs_net_send and iotjs_net_recv functions + iotjs_bio_init(&(tls_data->bio.receive_bio), SSL_BIO_SIZE); + iotjs_bio_init(&(tls_data->bio.send_bio), SSL_BIO_SIZE); + mbedtls_ssl_set_bio(&tls_data->ssl, &(tls_data->bio), iotjs_bio_net_send, + iotjs_bio_net_receive, NULL); + + return jerry_create_undefined(); +} + + +JS_FUNCTION(tls_connect) { + JS_DECLARE_THIS_PTR(tls, tls_data); + DJS_CHECK_ARGS(1, string); + + if (tls_data->state == TLS_HANDSHAKE_READY) { + iotjs_string_t server_name = JS_GET_ARG(0, string); + mbedtls_ssl_set_hostname(&tls_data->ssl, iotjs_string_data(&server_name)); + iotjs_string_destroy(&server_name); + } + + return jerry_create_undefined(); +} + + +static void iotjs_tls_send_pending(iotjs_tls_t *tls_data) { + iotjs_bio_t *send_bio = &(tls_data->bio.send_bio); + size_t pending = iotjs_bio_pending(send_bio); + + if (pending == 0) { + return; + } + + jerry_value_t jbuffer = iotjs_bufferwrap_create_buffer(pending); + iotjs_bufferwrap_t *buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuffer); + iotjs_bio_read(send_bio, buffer_wrap->buffer, pending); + + jerry_value_t jthis = tls_data->jobject; + jerry_value_t fn = iotjs_jval_get_property(jthis, IOTJS_MAGIC_STRING_ONWRITE); + + iotjs_invoke_callback(fn, jthis, &jbuffer, 1); + + jerry_release_value(fn); + jerry_release_value(jbuffer); +} + + +static void iotjs_tls_notify_error(iotjs_tls_t *tls_data) { + jerry_value_t jerror = jerry_create_string((const jerry_char_t *)"error"); + jerry_value_t jmessage = + jerry_create_string((const jerry_char_t *)"TLS error"); + + jerry_value_t jthis = tls_data->jobject; + jerry_value_t fn = iotjs_jval_get_property(jthis, IOTJS_MAGIC_STRING_EMIT); + + jerry_value_t jargv[2] = { jerror, jmessage }; + iotjs_invoke_callback(fn, jthis, jargv, 2); + + jerry_release_value(fn); + jerry_release_value(jargv[0]); + jerry_release_value(jargv[1]); +} + + +JS_FUNCTION(tls_write) { + JS_DECLARE_THIS_PTR(tls, tls_data); + + if (tls_data->state != TLS_CONNECTED) { + return jerry_create_null(); + } + + const unsigned char *data = NULL; + size_t length = 0; + bool is_end = false; + + if (jargc >= 1 && jerry_value_to_boolean(jargv[0])) { + jerry_value_t jbuffer = JS_GET_ARG(0, object); + + iotjs_bufferwrap_t *buf = iotjs_bufferwrap_from_jbuffer(jbuffer); + data = (const unsigned char *)buf->buffer; + length = iotjs_bufferwrap_length(buf); + } + + if (jargc >= 2 && jerry_value_to_boolean(jargv[1])) { + is_end = true; + } + + while (true) { + int ret_val = mbedtls_ssl_write(&tls_data->ssl, data, length); + + if ((int)length == ret_val) { + break; + } + + iotjs_tls_send_pending(tls_data); + + if (ret_val > 0) { + data += ret_val; + length -= (size_t)ret_val; + } else if (ret_val != MBEDTLS_ERR_SSL_WANT_WRITE) { + tls_data->state = TLS_CLOSED; + return jerry_create_null(); + } + } + + if (is_end) { + while (true) { + int ret_val = mbedtls_ssl_close_notify(&tls_data->ssl); + if (ret_val == 0) { + tls_data->state = TLS_CLOSED; + break; + } + + iotjs_tls_send_pending(tls_data); + + if (ret_val != MBEDTLS_ERR_SSL_WANT_WRITE) { + iotjs_tls_notify_error(tls_data); + tls_data->state = TLS_CLOSED; + return jerry_create_null(); + } + } + } + + /* Last package is returned as a buffer. */ + iotjs_bio_t *send_bio = &(tls_data->bio.send_bio); + size_t pending = iotjs_bio_pending(send_bio); + + jerry_value_t jbuffer = iotjs_bufferwrap_create_buffer(pending); + iotjs_bufferwrap_t *buf = iotjs_bufferwrap_from_jbuffer(jbuffer); + iotjs_bio_read(send_bio, buf->buffer, pending); + + return jbuffer; +} + + +static void tls_handshake(iotjs_tls_t *tls_data, jerry_value_t jthis) { + tls_data->state = TLS_HANDSHAKE_IN_PROGRESS; + // Continue handshaking process + int ret_val = mbedtls_ssl_handshake(&tls_data->ssl); + + iotjs_tls_send_pending(tls_data); + + bool error; + bool authorized; + + // Check whether handshake completed + if (ret_val == 0) { + tls_data->state = TLS_CONNECTED; + error = false; + authorized = mbedtls_ssl_get_verify_result(&tls_data->ssl) == 0; + } else { + if (ret_val == MBEDTLS_ERR_SSL_WANT_READ || + ret_val == MBEDTLS_ERR_SSL_WANT_WRITE) { + return; + } + + tls_data->state = TLS_CLOSED; + error = true; + authorized = false; + } + + // Result of certificate verification + jerry_value_t jargv[2] = { jerry_create_boolean(error), + jerry_create_boolean(authorized) }; + + jerry_value_t fn = + iotjs_jval_get_property(jthis, IOTJS_MAGIC_STRING_ONHANDSHAKEDONE); + iotjs_invoke_callback(fn, jthis, jargv, 2); + + jerry_release_value(fn); + jerry_release_value(jargv[0]); + jerry_release_value(jargv[1]); +} + + +JS_FUNCTION(tls_read) { + JS_DECLARE_THIS_PTR(tls, tls_data); + + if (tls_data->state == TLS_CLOSED) { + return jerry_create_boolean(false); + } + + iotjs_bio_t *receive_bio = &(tls_data->bio.receive_bio); + const char *data = NULL; + size_t length = 0; + + if (jargc >= 1 && jerry_value_to_boolean(jargv[0])) { + jerry_value_t jbuffer = JS_GET_ARG(0, object); + + iotjs_bufferwrap_t *buf = iotjs_bufferwrap_from_jbuffer(jbuffer); + data = buf->buffer; + length = iotjs_bufferwrap_length(buf); + } + + do { + size_t copy_size = iotjs_bio_remaining(receive_bio); + + if (copy_size > length) { + copy_size = length; + } + + iotjs_bio_write(receive_bio, data, copy_size); + data += copy_size; + length -= copy_size; + + if (tls_data->state != TLS_CONNECTED) { + IOTJS_ASSERT(tls_data->state == TLS_HANDSHAKE_READY || + tls_data->state == TLS_HANDSHAKE_IN_PROGRESS); + tls_handshake(tls_data, jthis); + + if (tls_data->state != TLS_CONNECTED) { + IOTJS_ASSERT(tls_data->state == TLS_HANDSHAKE_IN_PROGRESS || + tls_data->state == TLS_CLOSED); + + if (length > 0 && tls_data->state == TLS_HANDSHAKE_IN_PROGRESS) { + continue; + } + + bool result = (tls_data->state != TLS_CLOSED); + return jerry_create_boolean(result); + } + } + + while (true) { + int ret_val = mbedtls_ssl_read(&tls_data->ssl, NULL, 0); + iotjs_tls_send_pending(tls_data); + + if (ret_val == 0) { + size_t pending = mbedtls_ssl_get_bytes_avail(&tls_data->ssl); + + if (pending == 0) { + continue; + } + + jerry_value_t jbuffer = iotjs_bufferwrap_create_buffer(pending); + iotjs_bufferwrap_t *buf = iotjs_bufferwrap_from_jbuffer(jbuffer); + ret_val = mbedtls_ssl_read(&tls_data->ssl, (unsigned char *)buf->buffer, + pending); + + IOTJS_ASSERT(ret_val == (int)pending); + IOTJS_UNUSED(ret_val); + + jerry_value_t fn = + iotjs_jval_get_property(jthis, IOTJS_MAGIC_STRING_ONREAD); + iotjs_invoke_callback(fn, jthis, &jbuffer, 1); + + jerry_release_value(jbuffer); + jerry_release_value(fn); + continue; + } + + if (ret_val == MBEDTLS_ERR_SSL_WANT_READ) { + break; + } + + if (ret_val == MBEDTLS_ERR_SSL_WANT_WRITE) { + continue; + } + + tls_data->state = TLS_CLOSED; + + if (ret_val == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { + return jerry_create_boolean(true); + } + + iotjs_tls_notify_error(tls_data); + return jerry_create_boolean(false); + } + } while (length > 0); + + return jerry_create_boolean(true); +} + + +jerry_value_t iotjs_init_tls(void) { + jerry_value_t jtls = jerry_create_object(); + + iotjs_jval_set_method(jtls, IOTJS_MAGIC_STRING_CONNECT, tls_connect); + iotjs_jval_set_method(jtls, IOTJS_MAGIC_STRING_READ, tls_read); + iotjs_jval_set_method(jtls, IOTJS_MAGIC_STRING_TLSCONTEXT, tls_tlscontext); + iotjs_jval_set_method(jtls, IOTJS_MAGIC_STRING_TLSINIT, tls_init); + iotjs_jval_set_method(jtls, IOTJS_MAGIC_STRING_WRITE, tls_write); + + return jtls; +} diff --git a/src/modules/iotjs_module_tls.h b/src/modules/iotjs_module_tls.h new file mode 100644 index 0000000000..ba55aaabd1 --- /dev/null +++ b/src/modules/iotjs_module_tls.h @@ -0,0 +1,101 @@ +/* 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_TLS_H +#define IOTJS_MODULE_TLS_H + +#include "iotjs_def.h" +#include "mbedtls/certs.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/entropy.h" +#include "mbedtls/net.h" +#include "mbedtls/net_sockets.h" +#include "mbedtls/ssl.h" + +// Default certificate +const char SSL_CA_PEM[] = + "-----BEGIN CERTIFICATE-----\n" + "MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMX\n" + "R2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMT\n" + "Ckdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQL\n" + "ExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UE\n" + "AxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8o\n" + "mUVCxKs+IVSbC9N/hHD6ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7\n" + "SqbKSaZeqKeMWhG8eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQ\n" + "BoZfXklqtTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd\n" + "C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feq\n" + "CapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8E\n" + "BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IHV2ccHsBqBt5ZtJot39wZhi4w\n" + "NgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9iYWxzaWduLm5ldC9yb290LXIyLmNy\n" + "bDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEA\n" + "mYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkI\n" + "k7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRD\n" + "LenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd\n" + "AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7TBj0/VLZ\n" + "jmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==\n" + "-----END CERTIFICATE-----\n"; + +// Handshake states for tls context +enum { + TLS_HANDSHAKE_READY = 0, + TLS_HANDSHAKE_IN_PROGRESS = 1, + TLS_CONNECTED = 2, + TLS_CLOSED = 3 +}; + +typedef struct { + char *mem; + size_t size; + size_t read_index; + size_t write_index; +} iotjs_bio_t; + +typedef struct { + iotjs_bio_t receive_bio; + iotjs_bio_t send_bio; +} iotjs_bio_pair_t; + +enum { + SSL_BIO_SUCCESS = 0, + SSL_BIO_ERROR = -1, + SSL_BIO_UNSET = -2, + SSL_BIO_SIZE = 4096 +}; + +enum { SSL_CONTEXT_HAS_KEY = (1 << 0) }; + +typedef struct { + int ref_count; + uint32_t context_flags; + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_pk_context pkey; + mbedtls_x509_crt own_cert; + mbedtls_x509_crt cert_auth; +} iotjs_tls_context_t; + +typedef struct { + jerry_value_t jobject; + int state; + + iotjs_tls_context_t *tls_context; + mbedtls_ssl_config conf; + mbedtls_ssl_context ssl; + + iotjs_bio_pair_t bio; +} iotjs_tls_t; + +#endif /* IOTJS_MODULE_TLS_H */ diff --git a/src/modules/iotjs_module_uart.c b/src/modules/iotjs_module_uart.c index dd2a83bdf2..b7aefa873e 100644 --- a/src/modules/iotjs_module_uart.c +++ b/src/modules/iotjs_module_uart.c @@ -16,339 +16,251 @@ #include #include "iotjs_def.h" +#include "iotjs_module_buffer.h" #include "iotjs_module_uart.h" -#include "iotjs_objectwrap.h" +#include "iotjs_uv_handle.h" +#include "iotjs_uv_request.h" -static iotjs_uart_t* iotjs_uart_instance_from_jval(const iotjs_jval_t* juart); -IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(uart); +static void iotjs_uart_object_destroy(uv_handle_t* handle); -static iotjs_uart_t* iotjs_uart_create(const iotjs_jval_t* juart) { - iotjs_uart_t* uart = IOTJS_ALLOC(iotjs_uart_t); - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_uart_t, uart); - iotjs_jobjectwrap_initialize(&_this->jobjectwrap, juart, - &this_module_native_info); +static const jerry_object_native_info_t this_module_native_info = { + .free_cb = (jerry_object_native_free_callback_t)iotjs_uart_object_destroy, +}; - _this->device_fd = -1; - - return uart; -} - -static void iotjs_uart_destroy(iotjs_uart_t* uart) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_uart_t, uart); - iotjs_jobjectwrap_destroy(&_this->jobjectwrap); - iotjs_string_destroy(&_this->device_path); - IOTJS_RELEASE(uart); -} - - -#define THIS iotjs_uart_reqwrap_t* uart_reqwrap - - -static iotjs_uart_reqwrap_t* iotjs_uart_reqwrap_create( - const iotjs_jval_t* jcallback, iotjs_uart_t* uart, UartOp op) { - iotjs_uart_reqwrap_t* uart_reqwrap = IOTJS_ALLOC(iotjs_uart_reqwrap_t); - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_uart_reqwrap_t, uart_reqwrap); - - iotjs_reqwrap_initialize(&_this->reqwrap, jcallback, (uv_req_t*)&_this->req); - - _this->req_data.op = op; - _this->uart_instance = uart; - - return uart_reqwrap; -} - - -static void iotjs_uart_reqwrap_destroy(THIS) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_uart_reqwrap_t, uart_reqwrap); - iotjs_reqwrap_destroy(&_this->reqwrap); - IOTJS_RELEASE(uart_reqwrap); -} - - -static void iotjs_uart_reqwrap_dispatched(THIS) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_uart_reqwrap_t, uart_reqwrap); - iotjs_uart_reqwrap_destroy(uart_reqwrap); -} - - -static uv_work_t* iotjs_uart_reqwrap_req(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_uart_reqwrap_t, uart_reqwrap); - return &_this->req; -} +void iotjs_uart_object_destroy(uv_handle_t* handle) { + iotjs_uart_t* uart = (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(handle); -static const iotjs_jval_t* iotjs_uart_reqwrap_jcallback(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_uart_reqwrap_t, uart_reqwrap); - return iotjs_reqwrap_jcallback(&_this->reqwrap); + iotjs_uart_destroy_platform_data(uart->platform_data); + IOTJS_RELEASE(handle); } -static iotjs_uart_t* iotjs_uart_instance_from_jval(const iotjs_jval_t* juart) { - iotjs_jobjectwrap_t* jobjectwrap = iotjs_jobjectwrap_from_jobject(juart); - return (iotjs_uart_t*)jobjectwrap; -} - - -iotjs_uart_reqwrap_t* iotjs_uart_reqwrap_from_request(uv_work_t* req) { - return (iotjs_uart_reqwrap_t*)(iotjs_reqwrap_from_request((uv_req_t*)req)); +static void uart_worker(uv_work_t* work_req) { + iotjs_periph_data_t* worker_data = + (iotjs_periph_data_t*)IOTJS_UV_REQUEST_EXTRA_DATA(work_req); + uv_handle_t* uart_poll_handle = (uv_handle_t*)worker_data->data; + + switch (worker_data->op) { + case kUartOpOpen: + worker_data->result = iotjs_uart_open(uart_poll_handle); + break; + case kUartOpWrite: + worker_data->result = iotjs_uart_write(uart_poll_handle); + break; + case kUartOpClose: + iotjs_uv_handle_close(uart_poll_handle, iotjs_uart_handle_close_cb); + worker_data->result = true; + break; + default: + IOTJS_ASSERT(!"Invalid Operation"); + } } - -iotjs_uart_reqdata_t* iotjs_uart_reqwrap_data(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_uart_reqwrap_t, uart_reqwrap); - return &_this->req_data; +static void iotjs_uart_read_cb(uv_poll_t* req, int status, int events) { + iotjs_uart_t* uart = (iotjs_uart_t*)req->data; + char buf[UART_WRITE_BUFFER_SIZE]; + int i = read(uart->device_fd, buf, UART_WRITE_BUFFER_SIZE - 1); + if (i > 0) { + buf[i] = '\0'; + DDDLOG("%s - read length: %d", __func__, i); + jerry_value_t juart = IOTJS_UV_HANDLE_DATA(req)->jobject; + jerry_value_t jemit = + iotjs_jval_get_property(juart, IOTJS_MAGIC_STRING_EMIT); + IOTJS_ASSERT(jerry_value_is_function(jemit)); + + jerry_value_t str = + jerry_create_string((const jerry_char_t*)IOTJS_MAGIC_STRING_DATA); + + jerry_value_t jbuf = iotjs_bufferwrap_create_buffer((size_t)i); + iotjs_bufferwrap_t* buf_wrap = iotjs_bufferwrap_from_jbuffer(jbuf); + iotjs_bufferwrap_copy(buf_wrap, buf, (size_t)i); + + jerry_value_t jargs[] = { str, jbuf }; + jerry_value_t jres = + jerry_call_function(jemit, IOTJS_UV_HANDLE_DATA(req)->jobject, jargs, + 2); + IOTJS_ASSERT(!jerry_value_is_error(jres)); + + jerry_release_value(jres); + jerry_release_value(str); + jerry_release_value(jbuf); + jerry_release_value(jemit); + } } - -iotjs_uart_t* iotjs_uart_instance_from_reqwrap(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_uart_reqwrap_t, uart_reqwrap); - return _this->uart_instance; +void iotjs_uart_register_read_cb(uv_poll_t* uart_poll_handle) { + iotjs_uart_t* uart = + (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle); + uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get()); + uv_poll_init(loop, uart_poll_handle, uart->device_fd); + uv_poll_start(uart_poll_handle, UV_READABLE, iotjs_uart_read_cb); } - -#undef THIS - - -static bool iotjs_uart_close(iotjs_uart_t* uart) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_uart_t, uart); - uv_poll_t* poll_handle = &_this->poll_handle; - - if (_this->device_fd > 0) { - if (!uv_is_closing((uv_handle_t*)poll_handle)) { - uv_close((uv_handle_t*)poll_handle, NULL); +static jerry_value_t uart_set_configuration(iotjs_uart_t* uart, + jerry_value_t jconfig) { + jerry_value_t jbaud_rate = + iotjs_jval_get_property(jconfig, IOTJS_MAGIC_STRING_BAUDRATE); + if (jerry_value_is_undefined(jbaud_rate)) { + uart->baud_rate = 9600; + } else { + if (!jerry_value_is_number(jbaud_rate)) { + jerry_release_value(jbaud_rate); + return JS_CREATE_ERROR(TYPE, + "Bad configuration - baud rate must be a Number"); } - if (close(_this->device_fd) < 0) { - return false; + unsigned br = (unsigned)iotjs_jval_as_number(jbaud_rate); + jerry_release_value(jbaud_rate); + + if (br != 230400 && br != 115200 && br != 57600 && br != 38400 && + br != 19200 && br != 9600 && br != 4800 && br != 2400 && br != 1800 && + br != 1200 && br != 600 && br != 300 && br != 200 && br != 150 && + br != 134 && br != 110 && br != 75 && br != 50 && br != 0) { + return JS_CREATE_ERROR(TYPE, "Invalid baud rate"); } - } - - return true; -} - -static void iotjs_uart_write_worker(uv_work_t* work_req) { - UART_WORKER_INIT; - - if (!iotjs_uart_write(uart)) { - req_data->result = false; - return; + uart->baud_rate = br; } - req_data->result = true; -} - + jerry_value_t jdata_bits = + iotjs_jval_get_property(jconfig, IOTJS_MAGIC_STRING_DATABITS); + if (jerry_value_is_undefined(jdata_bits)) { + uart->data_bits = 8; + } else { + if (!jerry_value_is_number(jdata_bits)) { + jerry_release_value(jdata_bits); + return JS_CREATE_ERROR(TYPE, + "Bad configuration - data bits must be a Number"); + } + uint8_t db = (uint8_t)iotjs_jval_as_number(jdata_bits); + jerry_release_value(jdata_bits); -static void iotjs_uart_close_worker(uv_work_t* work_req) { - UART_WORKER_INIT; + if (db > 8 || db < 5) { + return JS_CREATE_ERROR(TYPE, "Invalid data bits"); + } - if (!iotjs_uart_close(uart)) { - req_data->result = false; - return; + uart->data_bits = db; } - req_data->result = true; + return jerry_create_undefined(); } +JS_FUNCTION(uart_constructor) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(1, object); + DJS_CHECK_ARG_IF_EXIST(1, function); -static void iotjs_uart_after_worker(uv_work_t* work_req, int status) { - iotjs_uart_reqwrap_t* req_wrap = iotjs_uart_reqwrap_from_request(work_req); - iotjs_uart_reqdata_t* req_data = iotjs_uart_reqwrap_data(req_wrap); - - iotjs_jargs_t jargs = iotjs_jargs_create(1); + // Create UART object + const jerry_value_t juart = JS_GET_THIS(); + uv_handle_t* uart_poll_handle = + iotjs_uv_handle_create(sizeof(uv_poll_t), juart, &this_module_native_info, + sizeof(iotjs_uart_t)); + iotjs_uart_t* uart = + (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle); + // TODO: merge platform data allocation into the handle allocation. + iotjs_uart_create_platform_data(uart); + uart->device_fd = -1; + + jerry_value_t jconfig = JS_GET_ARG(0, object); - if (status) { - iotjs_jval_t error = iotjs_jval_create_error("System error"); - iotjs_jargs_append_jval(&jargs, &error); - iotjs_jval_destroy(&error); - } else { - switch (req_data->op) { - case kUartOpOpen: { - if (!req_data->result) { - iotjs_jargs_append_error(&jargs, "Failed to open UART device"); - } else { - iotjs_jargs_append_null(&jargs); - } - break; - } - case kUartOpWrite: { - iotjs_uart_t* uart = iotjs_uart_instance_from_reqwrap(req_wrap); - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_uart_t, uart); - - iotjs_string_destroy(&_this->buf_data); - - if (!req_data->result) { - iotjs_jargs_append_error(&jargs, "Cannot write to device"); - } else { - iotjs_jargs_append_null(&jargs); - } - break; - } - case kUartOpClose: { - if (!req_data->result) { - iotjs_jargs_append_error(&jargs, "Failed to close UART device"); - } else { - iotjs_jargs_append_null(&jargs); - } - break; - } - default: { - IOTJS_ASSERT(!"Unreachable"); - break; - } - } + // set configuration + jerry_value_t res = iotjs_uart_set_platform_config(uart, jconfig); + if (jerry_value_is_error(res)) { + jerry_release_value(juart); + return res; } - const iotjs_jval_t* jcallback = iotjs_uart_reqwrap_jcallback(req_wrap); - iotjs_make_callback(jcallback, iotjs_jval_get_undefined(), &jargs); - - iotjs_jargs_destroy(&jargs); - iotjs_uart_reqwrap_dispatched(req_wrap); -} - - -static void iotjs_uart_onread(iotjs_jval_t* jthis, char* buf) { - iotjs_jval_t jemit = iotjs_jval_get_property(jthis, "emit"); - IOTJS_ASSERT(iotjs_jval_is_function(&jemit)); - - iotjs_jargs_t jargs = iotjs_jargs_create(2); - iotjs_jval_t str = iotjs_jval_create_string_raw("data"); - iotjs_jval_t data = iotjs_jval_create_string_raw(buf); - iotjs_jargs_append_jval(&jargs, &str); - iotjs_jargs_append_jval(&jargs, &data); - iotjs_jhelper_call_ok(&jemit, jthis, &jargs); - - iotjs_jval_destroy(&str); - iotjs_jval_destroy(&data); - iotjs_jargs_destroy(&jargs); - iotjs_jval_destroy(&jemit); -} + res = uart_set_configuration(uart, jconfig); + if (jerry_value_is_error(res)) { + jerry_release_value(juart); + return res; + } + DDDLOG("%s - baudRate: %d, dataBits: %d", __func__, uart->baud_rate, + uart->data_bits); -void iotjs_uart_read_cb(uv_poll_t* req, int status, int events) { - iotjs_uart_t* uart = (iotjs_uart_t*)req->data; - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_uart_t, uart); + jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(1, function); - char buf[UART_WRITE_BUFFER_SIZE]; - int i = read(_this->device_fd, buf, UART_WRITE_BUFFER_SIZE - 1); - if (i > 0) { - buf[i] = '\0'; - DDDLOG("%s - read data: %s", __func__, buf); - iotjs_uart_onread(&_this->jemitter_this, buf); + // If the callback doesn't exist, it is completed synchronously. + // Otherwise, it will be executed asynchronously. + if (!jerry_value_is_null(jcallback)) { + iotjs_periph_call_async(uart_poll_handle, jcallback, kUartOpOpen, + uart_worker); + } else if (!iotjs_uart_open(uart_poll_handle)) { + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kUartOpOpen)); } -} - - -#define UART_ASYNC(call, this, jcallback, op) \ - do { \ - uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get()); \ - iotjs_uart_reqwrap_t* req_wrap = \ - iotjs_uart_reqwrap_create(jcallback, this, op); \ - uv_work_t* req = iotjs_uart_reqwrap_req(req_wrap); \ - uv_queue_work(loop, req, iotjs_uart_##call##_worker, \ - iotjs_uart_after_worker); \ - } while (0) + return jerry_create_undefined(); +} -JHANDLER_FUNCTION(UartConstructor) { - DJHANDLER_CHECK_THIS(object); - DJHANDLER_CHECK_ARGS(3, object, object, function); +JS_FUNCTION(uart_write) { + JS_DECLARE_PTR(jthis, uv_poll_t, uart_poll_handle); + DJS_CHECK_ARGS(1, string); + DJS_CHECK_ARG_IF_EXIST(1, function); - // Create UART object - const iotjs_jval_t* juart = JHANDLER_GET_THIS(object); - iotjs_uart_t* uart = iotjs_uart_create(juart); - IOTJS_ASSERT(uart == iotjs_uart_instance_from_jval(juart)); - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_uart_t, uart); + iotjs_uart_t* uart = + (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle); + uart->buf_data = JS_GET_ARG(0, string); + uart->buf_len = iotjs_string_size(&uart->buf_data); - const iotjs_jval_t* jconfiguration = JHANDLER_GET_ARG(0, object); - const iotjs_jval_t* jemitter_this = JHANDLER_GET_ARG(1, object); - _this->jemitter_this = iotjs_jval_create_copied(jemitter_this); - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG(2, function); + iotjs_periph_call_async(uart_poll_handle, JS_GET_ARG_IF_EXIST(1, function), + kUartOpWrite, uart_worker); - // set configuration - iotjs_jval_t jdevice = - iotjs_jval_get_property(jconfiguration, IOTJS_MAGIC_STRING_DEVICE); - iotjs_jval_t jbaud_rate = - iotjs_jval_get_property(jconfiguration, IOTJS_MAGIC_STRING_BAUDRATE); - iotjs_jval_t jdata_bits = - iotjs_jval_get_property(jconfiguration, IOTJS_MAGIC_STRING_DATABITS); - - _this->device_path = iotjs_jval_as_string(&jdevice); - _this->baud_rate = iotjs_jval_as_number(&jbaud_rate); - _this->data_bits = iotjs_jval_as_number(&jdata_bits); - - DDDLOG("%s - path: %s, baudRate: %d, dataBits: %d", __func__, - iotjs_string_data(&_this->device_path), _this->baud_rate, - _this->data_bits); - - iotjs_jval_destroy(&jdevice); - iotjs_jval_destroy(&jbaud_rate); - iotjs_jval_destroy(&jdata_bits); - - UART_ASYNC(open, uart, jcallback, kUartOpOpen); + return jerry_create_undefined(); } +JS_FUNCTION(uart_write_sync) { + JS_DECLARE_PTR(jthis, uv_handle_t, uart_poll_handle); + DJS_CHECK_ARGS(1, string); -JHANDLER_FUNCTION(Write) { - JHANDLER_DECLARE_THIS_PTR(uart, uart); - DJHANDLER_CHECK_ARGS(1, string); - DJHANDLER_CHECK_ARG_IF_EXIST(1, function); - - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(1, function); + iotjs_uart_t* uart = + (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle); + uart->buf_data = JS_GET_ARG(0, string); + uart->buf_len = iotjs_string_size(&uart->buf_data); - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_uart_t, uart); + bool result = iotjs_uart_write(uart_poll_handle); + iotjs_string_destroy(&uart->buf_data); - _this->buf_data = JHANDLER_GET_ARG(0, string); - _this->buf_len = iotjs_string_size(&_this->buf_data); - - if (jcallback) { - UART_ASYNC(write, uart, jcallback, kUartOpWrite); - } else { - bool result = iotjs_uart_write(uart); - iotjs_string_destroy(&_this->buf_data); - - if (!result) { - JHANDLER_THROW(COMMON, "UART Write Error"); - return; - } + if (!result) { + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kUartOpWrite)); } - iotjs_jhandler_return_null(jhandler); + return jerry_create_undefined(); } +JS_FUNCTION(uart_close) { + JS_DECLARE_PTR(jthis, uv_poll_t, uart_poll_handle); + DJS_CHECK_ARG_IF_EXIST(0, function); -JHANDLER_FUNCTION(Close) { - JHANDLER_DECLARE_THIS_PTR(uart, uart); - DJHANDLER_CHECK_ARG_IF_EXIST(0, function); - - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG_IF_EXIST(0, function); + iotjs_periph_call_async(uart_poll_handle, JS_GET_ARG_IF_EXIST(0, function), + kUartOpClose, uart_worker); - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_uart_t, uart); - iotjs_jval_destroy(&_this->jemitter_this); - - if (jcallback) { - UART_ASYNC(close, uart, jcallback, kUartOpClose); - } else { - if (!iotjs_uart_close(uart)) { - JHANDLER_THROW(COMMON, "UART Close Error"); - } - } + return jerry_create_undefined(); } +JS_FUNCTION(uart_close_sync) { + JS_DECLARE_PTR(jthis, uv_handle_t, uart_poll_handle); -iotjs_jval_t InitUart() { - iotjs_jval_t juart_constructor = - iotjs_jval_create_function_with_dispatch(UartConstructor); + iotjs_uv_handle_close(uart_poll_handle, iotjs_uart_handle_close_cb); + return jerry_create_undefined(); +} - iotjs_jval_t prototype = iotjs_jval_create_object(); +jerry_value_t iotjs_init_uart(void) { + jerry_value_t juart_cons = jerry_create_external_function(uart_constructor); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_WRITE, Write); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_CLOSE, Close); + jerry_value_t prototype = jerry_create_object(); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_WRITE, uart_write); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_WRITESYNC, + uart_write_sync); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_CLOSE, uart_close); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_CLOSESYNC, + uart_close_sync); - iotjs_jval_set_property_jval(&juart_constructor, IOTJS_MAGIC_STRING_PROTOTYPE, - &prototype); + iotjs_jval_set_property_jval(juart_cons, IOTJS_MAGIC_STRING_PROTOTYPE, + prototype); - iotjs_jval_destroy(&prototype); + jerry_release_value(prototype); - return juart_constructor; + return juart_cons; } diff --git a/src/modules/iotjs_module_uart.h b/src/modules/iotjs_module_uart.h index 3b1c72f9e0..1cec3bb844 100644 --- a/src/modules/iotjs_module_uart.h +++ b/src/modules/iotjs_module_uart.h @@ -18,65 +18,32 @@ #define IOTJS_MODULE_UART_H #include "iotjs_def.h" -#include "iotjs_objectwrap.h" -#include "iotjs_reqwrap.h" +#include "iotjs_module_periph_common.h" #define UART_WRITE_BUFFER_SIZE 512 - -typedef enum { - kUartOpOpen, - kUartOpClose, - kUartOpWrite, -} UartOp; - +typedef struct iotjs_uart_platform_data_s iotjs_uart_platform_data_t; typedef struct { - iotjs_jobjectwrap_t jobjectwrap; - iotjs_jval_t jemitter_this; int device_fd; - int baud_rate; + unsigned baud_rate; uint8_t data_bits; - iotjs_string_t device_path; iotjs_string_t buf_data; unsigned buf_len; - uv_poll_t poll_handle; -} IOTJS_VALIDATED_STRUCT(iotjs_uart_t); - - -typedef struct { - UartOp op; - bool result; -} iotjs_uart_reqdata_t; - - -typedef struct { - iotjs_reqwrap_t reqwrap; - uv_work_t req; - iotjs_uart_reqdata_t req_data; - iotjs_uart_t* uart_instance; -} IOTJS_VALIDATED_STRUCT(iotjs_uart_reqwrap_t); - -#define THIS iotjs_uart_reqwrap_t* uart_reqwrap - -iotjs_uart_reqwrap_t* iotjs_uart_reqwrap_from_request(uv_work_t* req); -iotjs_uart_reqdata_t* iotjs_uart_reqwrap_data(THIS); - -iotjs_uart_t* iotjs_uart_instance_from_reqwrap(THIS); - -#undef THIS - -#define UART_WORKER_INIT \ - iotjs_uart_reqwrap_t* req_wrap = iotjs_uart_reqwrap_from_request(work_req); \ - iotjs_uart_reqdata_t* req_data = iotjs_uart_reqwrap_data(req_wrap); \ - iotjs_uart_t* uart = iotjs_uart_instance_from_reqwrap(req_wrap); + iotjs_uart_platform_data_t* platform_data; +} iotjs_uart_t; +void iotjs_uart_handle_close_cb(uv_handle_t* handle); +void iotjs_uart_register_read_cb(uv_poll_t* uart_poll_handle); -void iotjs_uart_read_cb(uv_poll_t* req, int status, int events); +void iotjs_uart_create_platform_data(iotjs_uart_t* uart); +jerry_value_t iotjs_uart_set_platform_config(iotjs_uart_t* uart, + const jerry_value_t jconfig); +void iotjs_uart_destroy_platform_data(iotjs_uart_platform_data_t* pdata); -void iotjs_uart_open_worker(uv_work_t* work_req); -bool iotjs_uart_write(iotjs_uart_t* uart); +bool iotjs_uart_open(uv_handle_t* uart_poll_handle); +bool iotjs_uart_write(uv_handle_t* uart_poll_handle); #endif /* IOTJS_MODULE_UART_H */ diff --git a/src/modules/iotjs_module_udp.c b/src/modules/iotjs_module_udp.c index 635cd7adbc..3e95eb1fef 100644 --- a/src/modules/iotjs_module_udp.c +++ b/src/modules/iotjs_module_udp.c @@ -15,139 +15,49 @@ #include "iotjs_def.h" -#include "iotjs_module_udp.h" - -#include "iotjs_handlewrap.h" #include "iotjs_module_buffer.h" #include "iotjs_module_tcp.h" -#include "iotjs_reqwrap.h" - +#include "iotjs_uv_handle.h" +#include "iotjs_uv_request.h" -IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(udpwrap); +static const jerry_object_native_info_t this_module_native_info = { NULL }; -iotjs_udpwrap_t* iotjs_udpwrap_create(const iotjs_jval_t* judp) { - iotjs_udpwrap_t* udpwrap = IOTJS_ALLOC(iotjs_udpwrap_t); - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_udpwrap_t, udpwrap); - iotjs_handlewrap_initialize(&_this->handlewrap, judp, - (uv_handle_t*)(&_this->handle), - &this_module_native_info); +void iotjs_udp_object_init(jerry_value_t judp) { + uv_handle_t* handle = iotjs_uv_handle_create(sizeof(uv_udp_t), judp, + &this_module_native_info, 0); const iotjs_environment_t* env = iotjs_environment_get(); - uv_udp_init(iotjs_environment_loop(env), &_this->handle); - - return udpwrap; + uv_udp_init(iotjs_environment_loop(env), (uv_udp_t*)handle); } -static void iotjs_udpwrap_destroy(iotjs_udpwrap_t* udpwrap) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_udpwrap_t, udpwrap); - iotjs_handlewrap_destroy(&_this->handlewrap); - IOTJS_RELEASE(udpwrap); -} - - -iotjs_udpwrap_t* iotjs_udpwrap_from_handle(uv_udp_t* udp_handle) { - uv_handle_t* handle = (uv_handle_t*)(udp_handle); - iotjs_handlewrap_t* handlewrap = iotjs_handlewrap_from_handle(handle); - iotjs_udpwrap_t* udpwrap = (iotjs_udpwrap_t*)handlewrap; - IOTJS_ASSERT(iotjs_udpwrap_udp_handle(udpwrap) == udp_handle); - return udpwrap; -} - - -iotjs_udpwrap_t* iotjs_udpwrap_from_jobject(const iotjs_jval_t* judp) { - iotjs_handlewrap_t* handlewrap = iotjs_handlewrap_from_jobject(judp); - return (iotjs_udpwrap_t*)handlewrap; -} - - -uv_udp_t* iotjs_udpwrap_udp_handle(iotjs_udpwrap_t* udpwrap) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_udpwrap_t, udpwrap); - uv_handle_t* handle = iotjs_handlewrap_get_uv_handle(&_this->handlewrap); - return (uv_udp_t*)handle; -} +JS_FUNCTION(udp_constructor) { + DJS_CHECK_THIS(); + jerry_value_t judp = JS_GET_THIS(); + iotjs_udp_object_init(judp); -iotjs_jval_t* iotjs_udpwrap_jobject(iotjs_udpwrap_t* udpwrap) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_udpwrap_t, udpwrap); - return iotjs_handlewrap_jobject(&_this->handlewrap); + return jerry_create_undefined(); } -#define THIS iotjs_send_reqwrap_t* send_reqwrap +JS_FUNCTION(udp_bind) { + JS_DECLARE_PTR(jthis, uv_udp_t, udp_handle); + DJS_CHECK_ARGS(2, string, number); -iotjs_send_reqwrap_t* iotjs_send_reqwrap_create(const iotjs_jval_t* jcallback, - const size_t msg_size) { - iotjs_send_reqwrap_t* send_reqwrap = IOTJS_ALLOC(iotjs_send_reqwrap_t); - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_send_reqwrap_t, send_reqwrap); - - iotjs_reqwrap_initialize(&_this->reqwrap, jcallback, (uv_req_t*)&_this->req); - _this->msg_size = msg_size; - - return send_reqwrap; -} - - -static void iotjs_send_reqwrap_destroy(THIS) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_send_reqwrap_t, send_reqwrap); - iotjs_reqwrap_destroy(&_this->reqwrap); - IOTJS_RELEASE(send_reqwrap); -} - - -void iotjs_send_reqwrap_dispatched(THIS) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_send_reqwrap_t, send_reqwrap); - iotjs_send_reqwrap_destroy(send_reqwrap); -} - - -uv_udp_send_t* iotjs_send_reqwrap_req(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_send_reqwrap_t, send_reqwrap); - return &_this->req; -} - - -const iotjs_jval_t* iotjs_send_reqwrap_jcallback(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_send_reqwrap_t, send_reqwrap); - return iotjs_reqwrap_jcallback(&_this->reqwrap); -} - - -size_t iotjs_send_reqwrap_msg_size(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_send_reqwrap_t, send_reqwrap); - return _this->msg_size; -} - -#undef THIS - - -JHANDLER_FUNCTION(UDP) { - DJHANDLER_CHECK_THIS(object); - DJHANDLER_CHECK_ARGS(0); - - const iotjs_jval_t* judp = JHANDLER_GET_THIS(object); - iotjs_udpwrap_t* udp_wrap = iotjs_udpwrap_create(judp); - IOTJS_UNUSED(udp_wrap); -} - - -JHANDLER_FUNCTION(Bind) { - JHANDLER_DECLARE_THIS_PTR(udpwrap, udp_wrap); - DJHANDLER_CHECK_ARGS(2, string, number); - - iotjs_string_t address = JHANDLER_GET_ARG(0, string); - const int port = JHANDLER_GET_ARG(1, number); - const iotjs_jval_t* this_obj = JHANDLER_GET_THIS(object); - iotjs_jval_t reuse_addr = + iotjs_string_t address = JS_GET_ARG(0, string); + const int port = JS_GET_ARG(1, number); + jerry_value_t this_obj = JS_GET_THIS(); + jerry_value_t reuse_addr = iotjs_jval_get_property(this_obj, IOTJS_MAGIC_STRING__REUSEADDR); - IOTJS_ASSERT(iotjs_jval_is_boolean(&reuse_addr) || - iotjs_jval_is_undefined(&reuse_addr)); + IOTJS_ASSERT(jerry_value_is_boolean(reuse_addr) || + jerry_value_is_undefined(reuse_addr)); unsigned int flags = 0; - if (!iotjs_jval_is_undefined(&reuse_addr)) { - flags = iotjs_jval_as_boolean(&reuse_addr) ? UV_UDP_REUSEADDR : 0; + if (!jerry_value_is_undefined(reuse_addr)) { + flags = iotjs_jval_as_boolean(reuse_addr) ? UV_UDP_REUSEADDR : 0; } char addr[sizeof(sockaddr_in6)]; @@ -155,18 +65,18 @@ JHANDLER_FUNCTION(Bind) { uv_ip4_addr(iotjs_string_data(&address), port, (sockaddr_in*)(&addr)); if (err == 0) { - err = uv_udp_bind(iotjs_udpwrap_udp_handle(udp_wrap), - (const sockaddr*)(&addr), flags); + err = uv_udp_bind(udp_handle, (const sockaddr*)(&addr), flags); } - iotjs_jhandler_return_number(jhandler, err); - - iotjs_jval_destroy(&reuse_addr); + jerry_release_value(reuse_addr); iotjs_string_destroy(&address); + + return jerry_create_number(err); } -static void OnAlloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { +static void on_alloc(uv_handle_t* handle, size_t suggested_size, + uv_buf_t* buf) { if (suggested_size > IOTJS_MAX_READ_BUFFER_SIZE) { suggested_size = IOTJS_MAX_READ_BUFFER_SIZE; } @@ -176,103 +86,92 @@ static void OnAlloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { } -static void OnRecv(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, - const struct sockaddr* addr, unsigned int flags) { +static void on_recv(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, + const struct sockaddr* addr, unsigned int flags) { if (nread == 0 && addr == NULL) { - if (buf->base != NULL) - iotjs_buffer_release(buf->base); + iotjs_buffer_release(buf->base); return; } - iotjs_udpwrap_t* udp_wrap = iotjs_udpwrap_from_handle(handle); - // udp handle - const iotjs_jval_t* judp = iotjs_udpwrap_jobject(udp_wrap); - IOTJS_ASSERT(iotjs_jval_is_object(judp)); + jerry_value_t judp = IOTJS_UV_HANDLE_DATA(handle)->jobject; + IOTJS_ASSERT(jerry_value_is_object(judp)); // onmessage callback - iotjs_jval_t jonmessage = + jerry_value_t jonmessage = iotjs_jval_get_property(judp, IOTJS_MAGIC_STRING_ONMESSAGE); - IOTJS_ASSERT(iotjs_jval_is_function(&jonmessage)); + IOTJS_ASSERT(jerry_value_is_function(jonmessage)); - iotjs_jargs_t jargs = iotjs_jargs_create(4); - iotjs_jargs_append_number(&jargs, nread); - iotjs_jargs_append_jval(&jargs, judp); + jerry_value_t jargs[4] = { jerry_create_number(nread), + jerry_acquire_value(judp), jerry_create_null(), + jerry_create_object() }; if (nread < 0) { - if (buf->base != NULL) - iotjs_buffer_release(buf->base); - iotjs_make_callback(&jonmessage, iotjs_jval_get_undefined(), &jargs); - iotjs_jval_destroy(&jonmessage); - iotjs_jargs_destroy(&jargs); + iotjs_buffer_release(buf->base); + iotjs_invoke_callback(jonmessage, jerry_create_undefined(), jargs, 2); + jerry_release_value(jonmessage); + + for (int i = 0; i < 4; i++) { + jerry_release_value(jargs[i]); + } return; } - iotjs_jval_t jbuffer = iotjs_bufferwrap_create_buffer((size_t)nread); - iotjs_bufferwrap_t* buffer_wrap = iotjs_bufferwrap_from_jbuffer(&jbuffer); - + jargs[2] = iotjs_bufferwrap_create_buffer((size_t)nread); + iotjs_bufferwrap_t* buffer_wrap = iotjs_bufferwrap_from_jbuffer(jargs[2]); iotjs_bufferwrap_copy(buffer_wrap, buf->base, (size_t)nread); + address_to_js(jargs[3], addr); - iotjs_jargs_append_jval(&jargs, &jbuffer); - - iotjs_jval_t rinfo = iotjs_jval_create_object(); - AddressToJS(&rinfo, addr); - iotjs_jargs_append_jval(&jargs, &rinfo); - - iotjs_make_callback(&jonmessage, iotjs_jval_get_undefined(), &jargs); + iotjs_invoke_callback(jonmessage, jerry_create_undefined(), jargs, 4); - iotjs_jval_destroy(&rinfo); - iotjs_jval_destroy(&jbuffer); - iotjs_jval_destroy(&jonmessage); + jerry_release_value(jonmessage); iotjs_buffer_release(buf->base); - iotjs_jargs_destroy(&jargs); + + for (int i = 0; i < 4; i++) { + jerry_release_value(jargs[i]); + } } -JHANDLER_FUNCTION(RecvStart) { - JHANDLER_DECLARE_THIS_PTR(udpwrap, udp_wrap); - DJHANDLER_CHECK_ARGS(0); +JS_FUNCTION(udp_recv_start) { + JS_DECLARE_PTR(jthis, uv_udp_t, udp_handle); - int err = - uv_udp_recv_start(iotjs_udpwrap_udp_handle(udp_wrap), OnAlloc, OnRecv); + int err = uv_udp_recv_start(udp_handle, on_alloc, on_recv); // UV_EALREADY means that the socket is already bound but that's okay if (err == UV_EALREADY) err = 0; - iotjs_jhandler_return_number(jhandler, err); + return jerry_create_number(err); } -JHANDLER_FUNCTION(RecvStop) { - JHANDLER_DECLARE_THIS_PTR(udpwrap, udp_wrap); - DJHANDLER_CHECK_ARGS(0); +JS_FUNCTION(udp_recv_stop) { + JS_DECLARE_PTR(jthis, uv_udp_t, udp_handle); - int r = uv_udp_recv_stop(iotjs_udpwrap_udp_handle(udp_wrap)); + int r = uv_udp_recv_stop(udp_handle); - iotjs_jhandler_return_number(jhandler, r); + return jerry_create_number(r); } -static void OnSend(uv_udp_send_t* req, int status) { - iotjs_send_reqwrap_t* req_wrap = (iotjs_send_reqwrap_t*)(req->data); - IOTJS_ASSERT(req_wrap != NULL); +static void on_send(uv_udp_send_t* req, int status) { + IOTJS_ASSERT(req != NULL); // Take callback function object. - const iotjs_jval_t* jcallback = iotjs_send_reqwrap_jcallback(req_wrap); + jerry_value_t jcallback = *IOTJS_UV_REQUEST_JSCALLBACK(req); - if (iotjs_jval_is_function(jcallback)) { - // Take callback function object. + if (jerry_value_is_function(jcallback)) { + size_t msg_size = *((size_t*)IOTJS_UV_REQUEST_EXTRA_DATA(req)); + jerry_value_t jargs[2] = { jerry_create_number(status), + jerry_create_number(msg_size) }; - iotjs_jargs_t jargs = iotjs_jargs_create(2); - iotjs_jargs_append_number(&jargs, status); - iotjs_jargs_append_number(&jargs, iotjs_send_reqwrap_msg_size(req_wrap)); - - iotjs_make_callback(jcallback, iotjs_jval_get_undefined(), &jargs); - iotjs_jargs_destroy(&jargs); + iotjs_invoke_callback(jcallback, jerry_create_undefined(), jargs, 2); + jerry_release_value(jargs[0]); + jerry_release_value(jargs[1]); } - iotjs_send_reqwrap_dispatched(req_wrap); + iotjs_uv_request_destroy((uv_req_t*)req); } @@ -281,25 +180,33 @@ static void OnSend(uv_udp_send_t* req, int status) { // [1] port // [2] ip // [3] callback function -JHANDLER_FUNCTION(Send) { - JHANDLER_DECLARE_THIS_PTR(udpwrap, udp_wrap); - DJHANDLER_CHECK_ARGS(3, object, number, string); - IOTJS_ASSERT(iotjs_jval_is_function(iotjs_jhandler_get_arg(jhandler, 3)) || - iotjs_jval_is_undefined(iotjs_jhandler_get_arg(jhandler, 3))); - - const iotjs_jval_t* jbuffer = JHANDLER_GET_ARG(0, object); - const unsigned short port = JHANDLER_GET_ARG(1, number); - iotjs_string_t address = JHANDLER_GET_ARG(2, string); - const iotjs_jval_t* jcallback = JHANDLER_GET_ARG(3, object); - - iotjs_bufferwrap_t* buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuffer); - char* buffer = iotjs_bufferwrap_buffer(buffer_wrap); +JS_FUNCTION(udp_send) { + JS_DECLARE_PTR(jthis, uv_udp_t, udp_handle); + DJS_CHECK_ARGS(3, object, number, string); + + if (!jerry_value_is_undefined(jargv[3]) && + !jerry_value_is_function(jargv[3])) { + return JS_CREATE_ERROR(TYPE, "Invalid callback given"); + } + + const jerry_value_t jbuffer = JS_GET_ARG(0, object); + const unsigned short port = JS_GET_ARG(1, number); + iotjs_string_t address = JS_GET_ARG(2, string); + jerry_value_t jcallback = JS_GET_ARG(3, object); + + iotjs_bufferwrap_t* buffer_wrap = iotjs_jbuffer_get_bufferwrap_ptr(jbuffer); + if (buffer_wrap == NULL) { + return JS_CREATE_ERROR(TYPE, "Invalid buffer given"); + } + size_t len = iotjs_bufferwrap_length(buffer_wrap); - iotjs_send_reqwrap_t* req_wrap = iotjs_send_reqwrap_create(jcallback, len); + uv_req_t* req_send = + iotjs_uv_request_create(sizeof(uv_udp_send_t), jcallback, sizeof(len)); + *((size_t*)IOTJS_UV_REQUEST_EXTRA_DATA(req_send)) = len; uv_buf_t buf; - buf.base = buffer; + buf.base = buffer_wrap->buffer; buf.len = len; char addr[sizeof(sockaddr_in6)]; @@ -307,182 +214,173 @@ JHANDLER_FUNCTION(Send) { uv_ip4_addr(iotjs_string_data(&address), port, (sockaddr_in*)(&addr)); if (err == 0) { - err = uv_udp_send(iotjs_send_reqwrap_req(req_wrap), - iotjs_udpwrap_udp_handle(udp_wrap), &buf, 1, - (const sockaddr*)(&addr), OnSend); + err = uv_udp_send((uv_udp_send_t*)req_send, udp_handle, &buf, 1, + (const sockaddr*)(&addr), on_send); } if (err) { - iotjs_send_reqwrap_dispatched(req_wrap); + iotjs_uv_request_destroy(req_send); } - iotjs_jhandler_return_number(jhandler, err); - iotjs_string_destroy(&address); -} - -// Close socket -JHANDLER_FUNCTION(Close) { - JHANDLER_DECLARE_THIS_PTR(handlewrap, wrap); - DJHANDLER_CHECK_ARGS(0); - - iotjs_handlewrap_close(wrap, NULL); + return jerry_create_number(err); } -GetSockNameFunction(udpwrap, udp_handle, uv_udp_getsockname); - - -JHANDLER_FUNCTION(GetSockeName) { - DoGetSockName(jhandler); -} - - -#define IOTJS_UV_SET_SOCKOPT(fn) \ - JHANDLER_DECLARE_THIS_PTR(udpwrap, udp_wrap); \ - DJHANDLER_CHECK_ARGS(1, number); \ - \ - int flag = JHANDLER_GET_ARG(0, number); \ - int err = fn(iotjs_udpwrap_udp_handle(udp_wrap), flag); \ - \ - iotjs_jhandler_return_number(jhandler, err); - - -JHANDLER_FUNCTION(SetBroadcast) { -#if !defined(__NUTTX__) && !defined(__TIZENRT__) - IOTJS_UV_SET_SOCKOPT(uv_udp_set_broadcast); -#else - IOTJS_ASSERT(!"Not implemented"); - - iotjs_jhandler_return_null(jhandler); -#endif -} - - -JHANDLER_FUNCTION(SetTTL) { -#if !defined(__NUTTX__) && !defined(__TIZENRT__) - IOTJS_UV_SET_SOCKOPT(uv_udp_set_ttl); -#else - IOTJS_ASSERT(!"Not implemented"); - - iotjs_jhandler_return_null(jhandler); -#endif -} - - -JHANDLER_FUNCTION(SetMulticastTTL) { -#if !defined(__NUTTX__) && !defined(__TIZENRT__) - IOTJS_UV_SET_SOCKOPT(uv_udp_set_multicast_ttl); -#else - IOTJS_ASSERT(!"Not implemented"); - - iotjs_jhandler_return_null(jhandler); -#endif -} - - -JHANDLER_FUNCTION(SetMulticastLoopback) { -#if !defined(__NUTTX__) && !defined(__TIZENRT__) - IOTJS_UV_SET_SOCKOPT(uv_udp_set_multicast_loop); +// Close socket +JS_FUNCTION(udp_close) { + JS_DECLARE_PTR(jthis, uv_handle_t, uv_handle); + + iotjs_uv_handle_close(uv_handle, NULL); + + return jerry_create_undefined(); +} + + +JS_FUNCTION(udp_get_socket_name) { + JS_DECLARE_PTR(jthis, uv_udp_t, udp_handle); + DJS_CHECK_ARGS(1, object); + + sockaddr_storage storage; + int addrlen = sizeof(storage); + sockaddr* const addr = (sockaddr*)(&storage); + int err = uv_udp_getsockname(udp_handle, addr, &addrlen); + if (err == 0) + address_to_js(JS_GET_ARG(0, object), addr); + return jerry_create_number(err); +} + + +// The order of these config types must match the order +// in the dgram js module. +enum config_type { BROADCAST, TTL, MULTICASTTTL, MULTICASTLOOPBACK }; + +JS_FUNCTION(udp_configure) { + JS_DECLARE_PTR(jthis, uv_udp_t, udp_handle); + DJS_CHECK_ARGS(2, number, number); + + jerry_value_t ret_value = jerry_create_null(); + +#if !defined(__NUTTX__) + enum config_type type = JS_GET_ARG(0, number); + int flag = JS_GET_ARG(1, number); + int (*fn)(uv_udp_t*, int) = NULL; + + switch (type) { + case BROADCAST: { + fn = &uv_udp_set_broadcast; + break; + } + case TTL: { + fn = &uv_udp_set_ttl; + break; + } + case MULTICASTTTL: { + fn = &uv_udp_set_multicast_ttl; + break; + } + case MULTICASTLOOPBACK: { + fn = &uv_udp_set_multicast_loop; + break; + } + default: { + IOTJS_ASSERT(!"Unknown config type"); + return jerry_create_null(); + } + } + ret_value = jerry_create_number(fn(udp_handle, flag)); #else IOTJS_ASSERT(!"Not implemented"); - - iotjs_jhandler_return_null(jhandler); #endif + return ret_value; } -#undef IOTJS_UV_SET_SOCKOPT +static jerry_value_t set_membership(const jerry_value_t jthis, + const jerry_value_t* jargv, + const jerry_length_t jargc, + uv_membership membership) { +#if !defined(__NUTTX__) + JS_DECLARE_PTR(jthis, uv_udp_t, udp_handle); + DJS_CHECK_ARGS(1, string); -void SetMembership(iotjs_jhandler_t* jhandler, uv_membership membership) { -#if !defined(__NUTTX__) && !defined(__TIZENRT__) - JHANDLER_DECLARE_THIS_PTR(udpwrap, udp_wrap); - DJHANDLER_CHECK_ARGS(1, string); - - iotjs_string_t address = JHANDLER_GET_ARG(0, string); - const iotjs_jval_t* arg1 = iotjs_jhandler_get_arg(jhandler, 1); - bool isUndefinedOrNull = - iotjs_jval_is_undefined(arg1) || iotjs_jval_is_null(arg1); + iotjs_string_t address = JS_GET_ARG(0, string); + bool is_undefined_or_null = + jerry_value_is_undefined(jargv[1]) || jerry_value_is_null(jargv[1]); iotjs_string_t iface; const char* iface_cstr; - if (isUndefinedOrNull) { + if (is_undefined_or_null) { iface_cstr = NULL; } else { - iface = iotjs_jval_as_string(arg1); + iface = iotjs_jval_as_string(jargv[1]); iface_cstr = iotjs_string_data(&iface); } - int err = uv_udp_set_membership(iotjs_udpwrap_udp_handle(udp_wrap), - iotjs_string_data(&address), iface_cstr, - membership); + int err = uv_udp_set_membership(udp_handle, iotjs_string_data(&address), + iface_cstr, membership); - iotjs_jhandler_return_number(jhandler, err); + if (!is_undefined_or_null) + iotjs_string_destroy(&iface); iotjs_string_destroy(&address); - if (!isUndefinedOrNull) - iotjs_string_destroy(&iface); + return jerry_create_number(err); #else IOTJS_ASSERT(!"Not implemented"); - iotjs_jhandler_return_null(jhandler); + return jerry_create_null(); #endif } -JHANDLER_FUNCTION(AddMembership) { - SetMembership(jhandler, UV_JOIN_GROUP); +JS_FUNCTION(udp_add_membership) { + return set_membership(jthis, jargv, jargc, UV_JOIN_GROUP); } -JHANDLER_FUNCTION(DropMembership) { - SetMembership(jhandler, UV_LEAVE_GROUP); +JS_FUNCTION(udp_drop_membership) { + return set_membership(jthis, jargv, jargc, UV_LEAVE_GROUP); } -JHANDLER_FUNCTION(Ref) { +JS_FUNCTION(udp_ref) { IOTJS_ASSERT(!"Not implemented"); - iotjs_jhandler_return_null(jhandler); + return jerry_create_null(); } -JHANDLER_FUNCTION(Unref) { +JS_FUNCTION(udp_unref) { IOTJS_ASSERT(!"Not implemented"); - iotjs_jhandler_return_null(jhandler); + return jerry_create_null(); } -iotjs_jval_t InitUdp() { - iotjs_jval_t udp = iotjs_jval_create_function_with_dispatch(UDP); - - iotjs_jval_t prototype = iotjs_jval_create_object(); - iotjs_jval_set_property_jval(&udp, IOTJS_MAGIC_STRING_PROTOTYPE, &prototype); - - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_BIND, Bind); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_RECVSTART, RecvStart); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_RECVSTOP, RecvStop); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_SEND, Send); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_CLOSE, Close); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_GETSOCKNAME, - GetSockeName); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_SETBROADCAST, - SetBroadcast); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_SETTTL, SetTTL); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_SETMULTICASTTTL, - SetMulticastTTL); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_SETMULTICASTLOOPBACK, - SetMulticastLoopback); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_ADDMEMBERSHIP, - AddMembership); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_DROPMEMBERSHIP, - DropMembership); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_REF, Ref); - iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_UNREF, Unref); - - iotjs_jval_destroy(&prototype); +jerry_value_t iotjs_init_udp(void) { + jerry_value_t udp = jerry_create_external_function(udp_constructor); + + jerry_value_t prototype = jerry_create_object(); + iotjs_jval_set_property_jval(udp, IOTJS_MAGIC_STRING_PROTOTYPE, prototype); + + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_BIND, udp_bind); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_RECVSTART, + udp_recv_start); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_RECVSTOP, udp_recv_stop); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_SEND, udp_send); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_CLOSE, udp_close); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_GETSOCKNAME, + udp_get_socket_name); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_CONFIGURE, udp_configure); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_ADDMEMBERSHIP, + udp_add_membership); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_DROPMEMBERSHIP, + udp_drop_membership); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_REF, udp_ref); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_UNREF, udp_unref); + + jerry_release_value(prototype); return udp; } diff --git a/src/modules/iotjs_module_udp.h b/src/modules/iotjs_module_udp.h deleted file mode 100644 index 2d9e669039..0000000000 --- a/src/modules/iotjs_module_udp.h +++ /dev/null @@ -1,60 +0,0 @@ -/* Copyright 2015-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_UDP_H -#define IOTJS_MODULE_UDP_H - - -#include "iotjs_def.h" -#include "iotjs_handlewrap.h" -#include "iotjs_reqwrap.h" - - -typedef struct { - iotjs_handlewrap_t handlewrap; - uv_udp_t handle; -} IOTJS_VALIDATED_STRUCT(iotjs_udpwrap_t); - - -iotjs_udpwrap_t* iotjs_udpwrap_create(const iotjs_jval_t* judp); - -iotjs_udpwrap_t* iotjs_udpwrap_from_handle(uv_udp_t* handle); -iotjs_udpwrap_t* iotjs_udpwrap_from_jobject(const iotjs_jval_t* judp); - -uv_udp_t* iotjs_udpwrap_udp_handle(iotjs_udpwrap_t* udpwrap); -iotjs_jval_t* iotjs_udpwrap_jobject(iotjs_udpwrap_t* udpwrap); - - -typedef struct { - iotjs_reqwrap_t reqwrap; - uv_udp_send_t req; - size_t msg_size; -} IOTJS_VALIDATED_STRUCT(iotjs_send_reqwrap_t); - -#define THIS iotjs_send_reqwrap_t* send_reqwrap - -iotjs_send_reqwrap_t* iotjs_send_reqwrap_create(const iotjs_jval_t* jcallback, - const size_t msg_size); - -void iotjs_send_reqwrap_dispatched(THIS); - -uv_udp_send_t* iotjs_send_reqwrap_req(THIS); -const iotjs_jval_t* iotjs_send_reqwrap_jcallback(THIS); - -#undef THIS - - -#endif /* IOTJS_MODULE_UDP_H */ diff --git a/src/modules/iotjs_module_websocket.c b/src/modules/iotjs_module_websocket.c new file mode 100644 index 0000000000..b47bee3fd3 --- /dev/null +++ b/src/modules/iotjs_module_websocket.c @@ -0,0 +1,797 @@ +/* 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 +#include + +#include "iotjs_def.h" +#include "iotjs_module_buffer.h" +#include "iotjs_module_crypto.h" +#include "iotjs_module_websocket.h" + + +IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(wsclient); + +static void iotjs_wsclient_destroy(iotjs_wsclient_t *wsclient) { + IOTJS_RELEASE(wsclient->tcp_buff.buffer); + IOTJS_RELEASE(wsclient->ws_buff.data); + IOTJS_RELEASE(wsclient->generated_key); + IOTJS_RELEASE(wsclient); +} + +iotjs_wsclient_t *iotjs_wsclient_create(const jerry_value_t jobject) { + iotjs_wsclient_t *wsclient = IOTJS_ALLOC(iotjs_wsclient_t); + + jerry_set_object_native_pointer(jobject, wsclient, &this_module_native_info); + return wsclient; +} + +static const char WS_GUID[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + +/** + * The protocol is as follows: + * method + USER_ENDPOINT + protocol + * host + USER_HOST + line_end + * upgrade + * connection + * sec_websocket_key + line_end + * sec_websocket_ver + */ +static const char method[] = "GET "; +static const char protocol[] = " HTTP/1.1\r\n"; +static const char host[] = "Host: "; +static const char line_end[] = "\r\n"; +static const char upgrade[] = "Upgrade: websocket\r\n"; +static const char connection[] = "Connection: Upgrade\r\n"; +static const char sec_websocket_key[] = "Sec-WebSocket-Key: "; +static const char sec_websocket_ver[] = "Sec-WebSocket-Version: 13\r\n\r\n"; +static const char handshake_response[] = + "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: " + "Upgrade\r\nSec-WebSocket-Accept: "; +static size_t header_fixed_size = + sizeof(method) + sizeof(protocol) + sizeof(host) + sizeof(upgrade) + + sizeof(connection) + sizeof(sec_websocket_key) + sizeof(sec_websocket_ver) - + 9; // 9 is for every \0 + + +void iotjs_websocket_create_callback(jerry_value_t jsref, jerry_value_t jmsg, + char *name, jerry_value_t client) { + jerry_value_t args[2]; + args[0] = jmsg; + args[1] = client; + jerry_value_t fn = iotjs_jval_get_property(jsref, name); + iotjs_invoke_callback(fn, jsref, args, 2); + + jerry_release_value(fn); +} + + +static unsigned char *ws_generate_key(jerry_value_t jsref, size_t *key_len) { + unsigned char *key = IOTJS_CALLOC(16, unsigned char); + for (int i = 0; i < 16; i++) { + key[i] = rand() % 256; + } + + unsigned char *ret_val = NULL; + + if (!(*key_len = iotjs_base64_encode(&ret_val, key, 16))) { + jerry_value_t ret_str = + jerry_create_string((jerry_char_t *)"mbedtls base64 encode failed"); + iotjs_websocket_create_callback(jsref, ret_str, IOTJS_MAGIC_STRING_ONERROR, + ret_str); + jerry_release_value(ret_str); + } + IOTJS_RELEASE(key); + + return ret_val; +} + + +static char *iotjs_ws_write_header(char *dst, const char *src) { + memcpy(dst, src, strlen(src)); + return dst + strlen(src); +} + + +static char *iotjs_ws_write_data(char *buff, void *data, size_t size) { + memcpy(buff, data, size); + return buff + size; +} + + +static unsigned char *iotjs_make_handshake_key(char *client_key, + size_t *key_len) { + unsigned char *out_buff = NULL; + + size_t ws_guid_size = strlen(WS_GUID); + size_t client_key_size = strnlen((char *)client_key, 24); + size_t concatenated_size = ws_guid_size + client_key_size; + + unsigned char concatenated[concatenated_size + 1]; + memcpy(concatenated, client_key, client_key_size); + memcpy(concatenated + client_key_size, WS_GUID, ws_guid_size); + concatenated[concatenated_size] = '\0'; + size_t out_buff_size = + iotjs_sha1_encode(&out_buff, concatenated, concatenated_size); + unsigned char *key_out = NULL; + if (!(*key_len = iotjs_base64_encode(&key_out, out_buff, out_buff_size))) { + key_out = NULL; + } + + IOTJS_RELEASE(out_buff); + return key_out; +} + +static bool iotjs_check_handshake_key(char *server_key, jerry_value_t jsref) { + bool ret_val = true; + void *native_p; + if (!jerry_get_object_native_pointer(jsref, &native_p, + &this_module_native_info)) { + ret_val = false; + } + + iotjs_wsclient_t *wsclient = (iotjs_wsclient_t *)native_p; + size_t key_len = 0; + unsigned char *key; + if (!(key = iotjs_make_handshake_key((char *)wsclient->generated_key, + &key_len))) { + ret_val = false; + } + + if (key && strncmp(server_key, (const char *)key, key_len)) { + ret_val = false; + } + + IOTJS_RELEASE(wsclient->generated_key); + IOTJS_RELEASE(key); + + return ret_val; +} + + +static jerry_value_t iotjs_websocket_encode_frame(uint8_t opcode, bool mask, + bool compress, char *payload, + size_t payload_len) { + uint8_t header[2] = { 0 }; + + uint64_t buffer_size = payload_len + sizeof(header); + + header[0] |= WS_FIN_BIT; + header[0] |= opcode; + + if (compress) { + header[0] |= 0x40; + } + + if (mask) { + header[1] |= WS_MASK_BIT; + buffer_size += 4; // mask key size is 32 bits + } + + uint8_t extended_len_size = 0; + if (payload_len <= WS_ONE_BYTE_LENGTH) { + header[1] |= payload_len; + } else if (payload_len <= UINT16_MAX) { + header[1] |= WS_TWO_BYTES_LENGTH; + extended_len_size = 2; + } else { + header[1] |= WS_THREE_BYTES_LENGTH; + extended_len_size = 8; + } + + buffer_size += extended_len_size; + + jerry_value_t jframe = iotjs_bufferwrap_create_buffer(buffer_size); + iotjs_bufferwrap_t *frame_wrap = iotjs_bufferwrap_from_jbuffer(jframe); + char *buff_ptr = frame_wrap->buffer; + + *buff_ptr++ = (char)header[0]; + *buff_ptr++ = (char)header[1]; + + if (extended_len_size) { + if (extended_len_size == 2) { + uint16_t len = payload_len; + *buff_ptr++ = *((char *)&len + 1); + *buff_ptr++ = *((char *)&len); + } else { + uint64_t len = payload_len; + for (int8_t i = sizeof(uint64_t) - 1; i >= 0; i--) { + *buff_ptr++ = *((char *)&len + i); + } + } + } + + if (payload != NULL) { + if (mask) { + uint8_t key[4]; + for (uint8_t i = 0; i < sizeof(key); i++) { + key[i] = rand() % 256; + } + + buff_ptr = iotjs_ws_write_data(buff_ptr, key, sizeof(key)); + + for (size_t i = 0; i < payload_len; i++) { + payload[i] ^= key[i % 4]; + } + } + + buff_ptr = iotjs_ws_write_data(buff_ptr, payload, payload_len); + } + + return jframe; +} + + +static void iotjs_websocket_create_buffer_and_cb(char **buff_ptr, + uint32_t payload_len, + char *cb_type, + jerry_value_t jsref, + jerry_value_t client) { + if (payload_len > 0) { + jerry_value_t ret_buff = iotjs_bufferwrap_create_buffer(payload_len); + iotjs_bufferwrap_t *buff_wrap = iotjs_bufferwrap_from_jbuffer(ret_buff); + iotjs_ws_write_data(buff_wrap->buffer, *buff_ptr, payload_len); + *buff_ptr += payload_len; + iotjs_websocket_create_callback(jsref, ret_buff, cb_type, client); + jerry_release_value(ret_buff); + + return; + } + iotjs_websocket_create_callback(jsref, jerry_create_undefined(), cb_type, + client); +} + + +static jerry_value_t iotjs_websocket_check_error(uint8_t code) { + switch (code) { + case WS_ERR_INVALID_UTF8: { + return JS_CREATE_ERROR(COMMON, "Invalid UTF8 string in UTF8 message"); + } + + case WS_ERR_INVALID_TERMINATE_CODE: { + return JS_CREATE_ERROR(COMMON, "Invalid terminate code received"); + } + + case WS_ERR_UNKNOWN_OPCODE: { + return JS_CREATE_ERROR(COMMON, "Uknown opcode received"); + } + + case WS_ERR_NATIVE_POINTER_ERR: { + return JS_CREATE_ERROR(COMMON, "WebSocket native pointer unavailable"); + } + + case WS_ERR_FRAME_SIZE_LIMIT: { + return JS_CREATE_ERROR(COMMON, "Frame size received exceeds limit"); + } + + default: { return jerry_create_undefined(); }; + } +} + + +JS_FUNCTION(prepare_handshake_request) { + DJS_CHECK_THIS(); + + jerry_value_t jsref = JS_GET_ARG(0, object); + jerry_value_t jhost = JS_GET_ARG(1, any); + jerry_value_t jendpoint = JS_GET_ARG(2, any); + + iotjs_string_t l_host; + iotjs_string_t l_endpoint; + if (!(iotjs_jbuffer_as_string(jendpoint, &l_endpoint)) || + !(iotjs_jbuffer_as_string(jhost, &l_host))) { + return JS_CREATE_ERROR(COMMON, "Invalid host and/or path arguments!"); + }; + + iotjs_wsclient_t *wsclient = NULL; + if (!jerry_get_object_native_pointer(jsref, (void **)&wsclient, + &this_module_native_info)) { + return iotjs_websocket_check_error(WS_ERR_NATIVE_POINTER_ERR); + } + + size_t generated_key_len = 0; + wsclient->generated_key = ws_generate_key(jsref, &generated_key_len); + + jerry_value_t jfinal = iotjs_bufferwrap_create_buffer( + header_fixed_size + iotjs_string_size(&l_endpoint) + + iotjs_string_size(&l_host) + (sizeof(line_end) * 2) + generated_key_len); + + iotjs_bufferwrap_t *final_wrap = iotjs_bufferwrap_from_jbuffer(jfinal); + + char *buff_ptr = final_wrap->buffer; + buff_ptr = iotjs_ws_write_header(buff_ptr, method); + memcpy(buff_ptr, iotjs_string_data(&l_endpoint), + iotjs_string_size(&l_endpoint)); + buff_ptr += iotjs_string_size(&l_endpoint); + buff_ptr = iotjs_ws_write_header(buff_ptr, protocol); + buff_ptr = iotjs_ws_write_header(buff_ptr, host); + memcpy(buff_ptr, iotjs_string_data(&l_host), iotjs_string_size(&l_host)); + buff_ptr += iotjs_string_size(&l_host); + buff_ptr = iotjs_ws_write_header(buff_ptr, line_end); + buff_ptr = iotjs_ws_write_header(buff_ptr, upgrade); + buff_ptr = iotjs_ws_write_header(buff_ptr, connection); + buff_ptr = iotjs_ws_write_header(buff_ptr, sec_websocket_key); + memcpy(buff_ptr, wsclient->generated_key, generated_key_len); + buff_ptr += generated_key_len; + buff_ptr = iotjs_ws_write_header(buff_ptr, line_end); + buff_ptr = iotjs_ws_write_header(buff_ptr, sec_websocket_ver); + + iotjs_string_destroy(&l_endpoint); + iotjs_string_destroy(&l_host); + + return jfinal; +} + + +/** + * HTTP/1.1 101 Switching Protocols + * Upgrade: websocket + * Connection: Upgrade + * Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= + */ +JS_FUNCTION(receive_handshake_data) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(1, string); + + iotjs_string_t client_key = JS_GET_ARG(0, string); + + size_t key_len = 0; + unsigned char *key; + if (!(key = iotjs_make_handshake_key((char *)iotjs_string_data(&client_key), + &key_len))) { + return JS_CREATE_ERROR(COMMON, "mbedtls base64 encode failed"); + } + + jerry_value_t jfinal = iotjs_bufferwrap_create_buffer( + sizeof(handshake_response) - 1 + key_len + sizeof(line_end) * 2); + + iotjs_bufferwrap_t *final_wrap = iotjs_bufferwrap_from_jbuffer(jfinal); + char *buff_ptr = final_wrap->buffer; + buff_ptr = iotjs_ws_write_header(buff_ptr, handshake_response); + memcpy(buff_ptr, key, key_len); + buff_ptr += key_len; + buff_ptr = iotjs_ws_write_header(buff_ptr, line_end); + buff_ptr = iotjs_ws_write_header(buff_ptr, line_end); + + iotjs_string_destroy(&client_key); + IOTJS_RELEASE(key); + return jfinal; +} + +JS_FUNCTION(parse_handshake_data) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(2, object, object); + + jerry_value_t jbuffer = JS_GET_ARG(0, object); + iotjs_bufferwrap_t *buff_wrap = iotjs_bufferwrap_from_jbuffer(jbuffer); + if (buff_wrap->length < 12 || strncmp(buff_wrap->buffer + 9, "101", 3)) { + return JS_CREATE_ERROR(COMMON, "WebSocket connection failed"); + } + jerry_value_t jsref = JS_GET_ARG(1, object); + + char ws_accept[] = "Sec-WebSocket-Accept: "; + char *frame_end = strstr(buff_wrap->buffer, "\r\n\r\n"); + char *key_pos = strstr(buff_wrap->buffer, ws_accept) + strlen(ws_accept); + char key[28] = { 0 }; + memcpy(key, key_pos, 28); + + frame_end += 4; // \r\n\r\n + + if (!iotjs_check_handshake_key(key, jsref)) { + return JS_CREATE_ERROR(COMMON, "WebSocket handshake key comparison failed"); + } + + size_t header_size = (size_t)(frame_end - buff_wrap->buffer); + if (buff_wrap->length > header_size) { + size_t remaining_length = buff_wrap->length - header_size; + jerry_value_t jdata = iotjs_bufferwrap_create_buffer(remaining_length); + iotjs_bufferwrap_t *data_wrap = iotjs_bufferwrap_from_jbuffer(jdata); + + memcpy(data_wrap->buffer, buff_wrap->buffer + header_size, + remaining_length); + data_wrap->length = remaining_length; + + return jdata; + } + + return jerry_create_undefined(); +} + + +static void iotjs_websocket_concat_tcp_buffers(iotjs_wsclient_t *wsclient, + iotjs_bufferwrap_t *buff_recv) { + char *tmp_buf = wsclient->tcp_buff.buffer; + wsclient->tcp_buff.buffer = + IOTJS_CALLOC(wsclient->tcp_buff.length + buff_recv->length, char); + memcpy(wsclient->tcp_buff.buffer, tmp_buf, wsclient->tcp_buff.length); + memcpy(wsclient->tcp_buff.buffer + wsclient->tcp_buff.length, + buff_recv->buffer, buff_recv->length); + wsclient->tcp_buff.length += buff_recv->length; + IOTJS_RELEASE(tmp_buf); +} + + +static uint8_t iotjs_websocket_decode_frame(iotjs_wsclient_t *wsclient, + char *first_byte, char *buff_ptr, + uint32_t payload_len, + jerry_value_t jsref, bool mask, + jerry_value_t client) { + uint8_t fin_bit = (first_byte[0] >> 7) & 0x01; + uint8_t opcode = first_byte[0] & 0x0F; + + uint32_t *mask_key = NULL; + if (mask) { + mask_key = (uint32_t *)buff_ptr; + buff_ptr += sizeof(uint32_t); + + for (uint64_t i = 0; i < payload_len; i++) { + buff_ptr[i] ^= ((unsigned char *)(mask_key))[i % 4]; + } + } + + switch (opcode) { + case WS_OP_CONTINUE: { + if (wsclient->ws_buff.length == 0) { + wsclient->ws_buff.masked = mask; + wsclient->ws_buff.first_byte = first_byte[0]; + wsclient->ws_buff.data = IOTJS_CALLOC(payload_len, char); + memcpy(wsclient->ws_buff.data, buff_ptr, payload_len); + wsclient->ws_buff.length = payload_len; + break; + } + + char *tmp_ptr = wsclient->ws_buff.data; + uint32_t tmp_len = wsclient->ws_buff.length; + wsclient->ws_buff.data = + IOTJS_CALLOC(wsclient->ws_buff.length + payload_len, char); + memcpy(wsclient->ws_buff.data, tmp_ptr, tmp_len); + memcpy(wsclient->ws_buff.data + tmp_len, buff_ptr, payload_len); + wsclient->ws_buff.length += payload_len; + IOTJS_RELEASE(tmp_ptr); + + + if (fin_bit) { + uint8_t ret_val = + iotjs_websocket_decode_frame(wsclient, + &wsclient->ws_buff.first_byte, + wsclient->ws_buff.data, + wsclient->ws_buff.length, jsref, + wsclient->ws_buff.masked, client); + + IOTJS_RELEASE(wsclient->ws_buff.data); + wsclient->ws_buff.length = 0; + wsclient->ws_buff.first_byte = 0; + + return ret_val; + } + break; + } + + case WS_OP_UTF8: + case WS_OP_BINARY: { + if (opcode == WS_OP_UTF8 && + !jerry_is_valid_utf8_string((unsigned char *)buff_ptr, payload_len)) { + return WS_ERR_INVALID_UTF8; + } + iotjs_websocket_create_buffer_and_cb(&buff_ptr, payload_len, + IOTJS_MAGIC_STRING_ONMESSAGE, jsref, + client); + break; + } + + case WS_OP_TERMINATE: { + if (payload_len > 0) { + uint16_t ret_code = (uint16_t)((unsigned char)buff_ptr[0] << 8 | + (unsigned char)buff_ptr[1]); + if (ret_code > 4999 || ret_code < 1000) { + return WS_ERR_INVALID_TERMINATE_CODE; + } + + buff_ptr += 2; + payload_len -= 2; + size_t ret_code_str_size = 4; + char ret_code_str[ret_code_str_size + 1]; + snprintf(ret_code_str, ret_code_str_size + 1, "%d", ret_code); + + jerry_value_t ret_buff = + iotjs_bufferwrap_create_buffer(payload_len + ret_code_str_size); + iotjs_bufferwrap_t *ret_wrap = iotjs_bufferwrap_from_jbuffer(ret_buff); + char *local_ptr = ret_wrap->buffer; + local_ptr = + iotjs_ws_write_data(local_ptr, ret_code_str, ret_code_str_size); + local_ptr = iotjs_ws_write_data(local_ptr, buff_ptr, payload_len); + buff_ptr += payload_len; + iotjs_websocket_create_callback(jsref, ret_buff, + IOTJS_MAGIC_STRING_ONCLOSE, client); + jerry_release_value(ret_buff); + break; + } + iotjs_websocket_create_callback(jsref, jerry_create_undefined(), + IOTJS_MAGIC_STRING_ONCLOSE, client); + break; + } + + case WS_OP_PING: { + iotjs_websocket_create_buffer_and_cb(&buff_ptr, payload_len, + IOTJS_MAGIC_STRING_PONG, jsref, + client); + break; + } + + case WS_OP_PONG: { + iotjs_websocket_create_buffer_and_cb(&buff_ptr, payload_len, + IOTJS_MAGIC_STRING_ONPINGRESP, jsref, + client); + break; + } + + default: + return WS_ERR_UNKNOWN_OPCODE; + break; + } + + return 0; +} + + +JS_FUNCTION(ws_receive) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(3, object, object, object); + + jerry_value_t jsref = JS_GET_ARG(0, object); + + iotjs_wsclient_t *wsclient = NULL; + if (!jerry_get_object_native_pointer(jsref, (void **)&wsclient, + &this_module_native_info)) { + return iotjs_websocket_check_error(WS_ERR_NATIVE_POINTER_ERR); + } + + jerry_value_t jbuffer = JS_GET_ARG(1, object); + iotjs_bufferwrap_t *buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuffer); + + jerry_value_t client = JS_GET_ARG(2, object); + + if (buffer_wrap->length == 0) { + return jerry_create_undefined(); + } + + char *current_buffer = buffer_wrap->buffer; + char *current_buffer_end = current_buffer + buffer_wrap->length; + + if (wsclient->tcp_buff.length > 0) { + iotjs_websocket_concat_tcp_buffers(wsclient, buffer_wrap); + current_buffer = wsclient->tcp_buff.buffer; + current_buffer_end = current_buffer + wsclient->tcp_buff.length; + } + + + while (true) { + if (current_buffer >= current_buffer_end) { + if (wsclient->tcp_buff.length > 0) { + IOTJS_RELEASE(wsclient->tcp_buff.buffer); + wsclient->tcp_buff.length = 0; + } + return jerry_create_undefined(); + } + + if (current_buffer + 2 > current_buffer_end) { + break; + } + + char *first_byte = current_buffer; + uint8_t payload_byte = (current_buffer[1]) & WS_THREE_BYTES_LENGTH; + uint8_t mask = (first_byte[1] >> 7) & 0x01; + + current_buffer += 2; + + uint32_t payload_len; + if (!(payload_byte ^ WS_TWO_BYTES_LENGTH)) { + if (current_buffer + sizeof(uint16_t) > current_buffer_end) { + break; + } + unsigned char *len_buffer = (unsigned char *)current_buffer; + payload_len = (uint16_t)(len_buffer[0] << 8 | len_buffer[1]); + current_buffer += sizeof(uint16_t); + } else if (!(payload_byte ^ WS_THREE_BYTES_LENGTH)) { + uint64_t payload_64bit_len; + if (current_buffer + sizeof(uint64_t) > current_buffer_end) { + break; + } + for (uint8_t i = 0; i < sizeof(uint64_t); i++) { + memcpy((uint8_t *)&payload_64bit_len + i, + current_buffer + sizeof(uint64_t) - 1 - i, sizeof(uint8_t)); + } + + if (payload_64bit_len > UINT32_MAX) { + return WS_ERR_FRAME_SIZE_LIMIT; + } + payload_len = (uint32_t)payload_64bit_len; + + current_buffer += sizeof(uint64_t); + } else { + payload_len = payload_byte; + } + + if (mask && ((current_buffer + 4 > current_buffer_end) || + (current_buffer + 4 + payload_len > current_buffer_end))) { + break; + } else if (!mask && (current_buffer + payload_len > current_buffer_end)) { + break; + } + + uint8_t ret_val = + iotjs_websocket_decode_frame(wsclient, first_byte, current_buffer, + payload_len, jsref, mask, client); + if (ret_val) { + return iotjs_websocket_check_error(ret_val); + } + + current_buffer += mask ? 4 : 0; + current_buffer += payload_len; + } + + if (current_buffer == wsclient->tcp_buff.buffer) { + return jerry_create_undefined(); + } + + uint32_t remaining_size = (uint32_t)(current_buffer_end - current_buffer); + char *buffer = IOTJS_CALLOC(remaining_size, char); + memcpy(buffer, current_buffer, remaining_size); + + if (wsclient->tcp_buff.buffer != NULL) { + IOTJS_RELEASE(wsclient->tcp_buff.buffer); + } + + wsclient->tcp_buff.buffer = buffer; + wsclient->tcp_buff.length = remaining_size; + + return jerry_create_undefined(); +} + + +JS_FUNCTION(ws_init) { + DJS_CHECK_THIS(); + + const jerry_value_t jws = JS_GET_ARG(0, object); + + iotjs_wsclient_t *wsclient = iotjs_wsclient_create(jws); + wsclient->tcp_buff.buffer = NULL; + wsclient->tcp_buff.length = 0; + + wsclient->ws_buff.data = NULL; + wsclient->ws_buff.length = 0; + + wsclient->generated_key = NULL; + + return jerry_create_undefined(); +} + + +JS_FUNCTION(ws_close) { + DJS_CHECK_THIS(); + + bool masked = false; + uint8_t opcode = WS_OP_TERMINATE; + iotjs_string_t payload = iotjs_string_create(); + + + jerry_value_t jmsg = JS_GET_ARG(0, any); + jerry_value_t jcode = JS_GET_ARG(1, any); + + iotjs_string_t msg = iotjs_string_create(); + // Client side close frame must be ALWAYS masked + masked = iotjs_jbuffer_as_string(jmsg, &msg) || jerry_value_is_number(jcode); + + if (jerry_value_is_number(jcode)) { + uint16_t code = jerry_get_number_value(jcode); + iotjs_string_append(&payload, (const char *)&code + 1, 1); + iotjs_string_append(&payload, (const char *)&code, 1); + } + + if (!iotjs_string_is_empty(&msg)) { + // We have no status code, but do have msg, append the status code + if (iotjs_string_is_empty(&payload)) { + uint16_t code = 1000; + iotjs_string_append(&payload, (const char *)&code + 1, 1); + iotjs_string_append(&payload, (const char *)&code, 1); + } + iotjs_string_append(&payload, iotjs_string_data(&msg), + iotjs_string_size(&msg)); + iotjs_string_destroy(&msg); + } + + jerry_value_t ret_val = + iotjs_websocket_encode_frame(opcode, masked, false, + (char *)iotjs_string_data(&payload), + iotjs_string_size(&payload)); + + if (payload.data != NULL) { + iotjs_string_destroy(&payload); + } + + return ret_val; +} + + +JS_FUNCTION(ws_send_data) { + DJS_CHECK_THIS(); + + jerry_value_t jmsg = JS_GET_ARG(0, any); + iotjs_string_t msg = iotjs_string_create(); + + if (!iotjs_jbuffer_as_string(jmsg, &msg)) { + return jerry_create_undefined(); + } + + bool binary = jerry_get_boolean_value(jargv[1]); + bool mask = jerry_get_boolean_value(jargv[2]); + bool compress = jerry_get_boolean_value(jargv[3]); + + uint8_t opcode = binary ? WS_OP_BINARY : WS_OP_UTF8; + + jerry_value_t ret_val = + iotjs_websocket_encode_frame(opcode, mask, compress, + (char *)iotjs_string_data(&msg), + iotjs_string_size(&msg)); + + iotjs_string_destroy(&msg); + return ret_val; +} + + +JS_FUNCTION(ws_ping_or_pong) { + DJS_CHECK_THIS(); + + uint8_t opcode = + jerry_get_boolean_value(JS_GET_ARG(0, any)) ? WS_OP_PING : WS_OP_PONG; + jerry_value_t jmsg = JS_GET_ARG(1, any); + + iotjs_string_t msg = iotjs_string_create(); + + jerry_value_t ret_val; + + if (iotjs_jbuffer_as_string(jmsg, &msg)) { + ret_val = + iotjs_websocket_encode_frame(opcode, jerry_get_boolean_value( + JS_GET_ARG(2, any)), + false, (char *)iotjs_string_data(&msg), + iotjs_string_size(&msg)); + iotjs_string_destroy(&msg); + } else { + ret_val = iotjs_websocket_encode_frame(opcode, false, false, NULL, 0); + } + + return ret_val; +} + + +jerry_value_t iotjs_init_websocket(void) { + IOTJS_UNUSED(WS_GUID); + + jerry_value_t jws = jerry_create_object(); + iotjs_jval_set_method(jws, IOTJS_MAGIC_STRING_CLOSE, ws_close); + iotjs_jval_set_method(jws, IOTJS_MAGIC_STRING_PARSEHANDSHAKEDATA, + parse_handshake_data); + iotjs_jval_set_method(jws, IOTJS_MAGIC_STRING_PING, ws_ping_or_pong); + iotjs_jval_set_method(jws, IOTJS_MAGIC_STRING_PREPAREHANDSHAKE, + prepare_handshake_request); + iotjs_jval_set_method(jws, IOTJS_MAGIC_STRING_SEND, ws_send_data); + iotjs_jval_set_method(jws, IOTJS_MAGIC_STRING_WSINIT, ws_init); + iotjs_jval_set_method(jws, IOTJS_MAGIC_STRING_WSRECEIVE, ws_receive); + iotjs_jval_set_method(jws, IOTJS_MAGIC_STRING_WSRECEIVEHANDSHAKEDATA, + receive_handshake_data); + + return jws; +} diff --git a/src/modules/iotjs_module_websocket.h b/src/modules/iotjs_module_websocket.h new file mode 100644 index 0000000000..b9237e7168 --- /dev/null +++ b/src/modules/iotjs_module_websocket.h @@ -0,0 +1,62 @@ +/* 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_WEBSOCKET_H +#define IOTJS_MODULE_WEBSOCKET_H + +enum { + WS_OP_CONTINUE = 0x00, + WS_OP_UTF8 = 0x01, + WS_OP_BINARY = 0x02, + WS_OP_TERMINATE = 0x08, + WS_OP_PING = 0x09, + WS_OP_PONG = 0x0a, +} iotjs_websocket_opcodes; + +enum { + WS_FIN_BIT = 0x80, + WS_MASK_BIT = WS_FIN_BIT, +} iotjs_websocket_header_bits; + +enum { + WS_ERR_INVALID_UTF8 = 1, + WS_ERR_INVALID_TERMINATE_CODE = 2, + WS_ERR_UNKNOWN_OPCODE = 3, + WS_ERR_NATIVE_POINTER_ERR = 4, + WS_ERR_FRAME_SIZE_LIMIT = 5, +} iotjs_websocket_err_codes; + +enum { + WS_ONE_BYTE_LENGTH = 125, + WS_TWO_BYTES_LENGTH, + WS_THREE_BYTES_LENGTH, +} iotjs_websocket_frame_len_types; + + +typedef struct { + struct { + uint32_t length; + char *buffer; + } tcp_buff; + + struct { + uint32_t length; + char *data; + char first_byte; + bool masked; + } ws_buff; + unsigned char *generated_key; +} iotjs_wsclient_t; + +#endif /* IOTJS_MODULE_WEBSOCKET_H */ diff --git a/src/platform/linux/iotjs_module_adc-linux.c b/src/modules/linux/iotjs_module_adc-linux.c similarity index 51% rename from src/platform/linux/iotjs_module_adc-linux.c rename to src/modules/linux/iotjs_module_adc-linux.c index 930370c5b6..50309fb504 100644 --- a/src/platform/linux/iotjs_module_adc-linux.c +++ b/src/modules/linux/iotjs_module_adc-linux.c @@ -13,8 +13,9 @@ * limitations under the License. */ -#ifndef IOTJS_MODULE_ADC_LINUX_GENERAL_INL_H -#define IOTJS_MODULE_ADC_LINUX_GENERAL_INL_H +#if !defined(__linux__) +#error "Module __FILE__ is for Linux only" +#endif #include #include @@ -24,28 +25,54 @@ #include "iotjs_systemio-linux.h" #include "modules/iotjs_module_adc.h" - #define ADC_PIN_FORMAT ADC_INTERFACE ADC_PIN_INTERFACE - #define ADC_PATH_BUFFER_SIZE DEVICE_IO_PATH_BUFFER_SIZE #define ADC_PIN_BUFFER_SIZE DEVICE_IO_PIN_BUFFER_SIZE #define ADC_VALUE_BUFFER_SIZE 64 +struct iotjs_adc_platform_data_s { + iotjs_string_t device; +}; + + +void iotjs_adc_create_platform_data(iotjs_adc_t* adc) { + adc->platform_data = IOTJS_ALLOC(iotjs_adc_platform_data_t); +} + + +void iotjs_adc_destroy_platform_data(iotjs_adc_platform_data_t* platform_data) { + iotjs_string_destroy(&platform_data->device); + IOTJS_RELEASE(platform_data); +} + + +jerry_value_t iotjs_adc_set_platform_config(iotjs_adc_t* adc, + const jerry_value_t jconfig) { + iotjs_adc_platform_data_t* platform_data = adc->platform_data; + + JS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->device, + IOTJS_MAGIC_STRING_DEVICE, string); + + return jerry_create_undefined(); +} + // Implementation used here are based on: // https://www.kernel.org/doc/Documentation/adc/sysfs.txt -int32_t iotjs_adc_read(iotjs_adc_t* adc) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_adc_t, adc); +bool iotjs_adc_read(iotjs_adc_t* adc) { + iotjs_adc_platform_data_t* platform_data = adc->platform_data; - const char* device_path = iotjs_string_data(&_this->device); + const char* device_path = iotjs_string_data(&platform_data->device); char buffer[ADC_VALUE_BUFFER_SIZE]; if (!iotjs_systemio_open_read_close(device_path, buffer, sizeof(buffer))) { - return -1; + return false; } - return atoi(buffer); + adc->value = atoi(buffer) != 0; + + return true; } @@ -53,16 +80,16 @@ bool iotjs_adc_close(iotjs_adc_t* adc) { return true; } -void iotjs_adc_open_worker(uv_work_t* work_req) { - ADC_WORKER_INIT; - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_adc_t, adc); +bool iotjs_adc_open(iotjs_adc_t* adc) { + iotjs_adc_platform_data_t* platform_data = adc->platform_data; DDDLOG("%s()", __func__); - const char* device_path = iotjs_string_data(&_this->device); + const char* device_path = iotjs_string_data(&platform_data->device); // Check if ADC interface exists. - req_data->result = iotjs_systemio_check_path(device_path); -} - + if (!iotjs_systemio_check_path(device_path)) { + return false; + } -#endif /* IOTJS_MODULE_ADC_LINUX_GENERAL_INL_H */ + return true; +} diff --git a/src/platform/linux/iotjs_module_blehcisocket-linux.c b/src/modules/linux/iotjs_module_blehcisocket-linux.c similarity index 59% rename from src/platform/linux/iotjs_module_blehcisocket-linux.c rename to src/modules/linux/iotjs_module_blehcisocket-linux.c index 776adfa77c..237f35d154 100644 --- a/src/platform/linux/iotjs_module_blehcisocket-linux.c +++ b/src/modules/linux/iotjs_module_blehcisocket-linux.c @@ -34,9 +34,6 @@ * SOFTWARE. */ -#ifndef IOTJS_MODULE_BLE_HCI_SOCKET_LINUX_GENERAL_INL_H -#define IOTJS_MODULE_BLE_HCI_SOCKET_LINUX_GENERAL_INL_H - #include #include #include @@ -143,42 +140,33 @@ struct sockaddr_l2 { }; -#define THIS iotjs_blehcisocket_t* blehcisocket - - -void iotjs_blehcisocket_initialize(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_blehcisocket_t, blehcisocket); +void iotjs_blehcisocket_initialize(iotjs_blehcisocket_t* blehcisocket) { + blehcisocket->_l2socketCount = 0; - _this->_l2socketCount = 0; - - _this->_socket = socket(AF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC, BTPROTO_HCI); + blehcisocket->_socket = + socket(AF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC, BTPROTO_HCI); uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get()); - uv_poll_init(loop, &(_this->_pollHandle), _this->_socket); + uv_poll_init(loop, &(blehcisocket->_pollHandle), blehcisocket->_socket); - _this->_pollHandle.data = blehcisocket; + blehcisocket->_pollHandle.data = blehcisocket; } -void iotjs_blehcisocket_close(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_blehcisocket_t, blehcisocket); - - uv_close((uv_handle_t*)&(_this->_pollHandle), NULL); +void iotjs_blehcisocket_close(iotjs_blehcisocket_t* blehcisocket) { + uv_close((uv_handle_t*)&(blehcisocket->_pollHandle), NULL); - close(_this->_socket); + close(blehcisocket->_socket); } -void iotjs_blehcisocket_start(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_blehcisocket_t, blehcisocket); - - uv_poll_start(&_this->_pollHandle, UV_READABLE, iotjs_blehcisocket_poll_cb); +void iotjs_blehcisocket_start(iotjs_blehcisocket_t* blehcisocket) { + uv_poll_start(&blehcisocket->_pollHandle, UV_READABLE, + iotjs_blehcisocket_poll_cb); } -int iotjs_blehcisocket_bindRaw(THIS, int* devId) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_blehcisocket_t, blehcisocket); - +int iotjs_blehcisocket_bindRaw(iotjs_blehcisocket_t* blehcisocket, int* devId) { struct sockaddr_hci a; struct hci_dev_info di; @@ -187,37 +175,36 @@ int iotjs_blehcisocket_bindRaw(THIS, int* devId) { a.hci_dev = iotjs_blehcisocket_devIdFor(blehcisocket, devId, true); a.hci_channel = HCI_CHANNEL_RAW; - _this->_devId = a.hci_dev; - _this->_mode = HCI_CHANNEL_RAW; + blehcisocket->_devId = a.hci_dev; + blehcisocket->_mode = HCI_CHANNEL_RAW; - if (bind(_this->_socket, (struct sockaddr*)&a, sizeof(a)) < 0) { + if (bind(blehcisocket->_socket, (struct sockaddr*)&a, sizeof(a)) < 0) { DLOG("ERROR on binding: %s", strerror(errno)); - return _this->_devId; + return blehcisocket->_devId; } // get the local address and address type memset(&di, 0x00, sizeof(di)); - di.dev_id = _this->_devId; - memset(_this->_address, 0, sizeof(_this->_address)); - _this->_addressType = 0; + di.dev_id = blehcisocket->_devId; + memset(blehcisocket->_address, 0, sizeof(blehcisocket->_address)); + blehcisocket->_addressType = 0; - if (ioctl(_this->_socket, HCIGETDEVINFO, (void*)&di) > -1) { - memcpy(_this->_address, &di.bdaddr, sizeof(di.bdaddr)); - _this->_addressType = di.type; + if (ioctl(blehcisocket->_socket, HCIGETDEVINFO, (void*)&di) > -1) { + memcpy(blehcisocket->_address, &di.bdaddr, sizeof(di.bdaddr)); + blehcisocket->_addressType = di.type; - if (_this->_addressType == 3) { + if (blehcisocket->_addressType == 3) { // 3 is a weird type, use 1 (public) instead - _this->_addressType = 1; + blehcisocket->_addressType = 1; } } - return _this->_devId; + return blehcisocket->_devId; } -int iotjs_blehcisocket_bindUser(THIS, int* devId) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_blehcisocket_t, blehcisocket); - +int iotjs_blehcisocket_bindUser(iotjs_blehcisocket_t* blehcisocket, + int* devId) { struct sockaddr_hci a; memset(&a, 0, sizeof(a)); @@ -225,20 +212,18 @@ int iotjs_blehcisocket_bindUser(THIS, int* devId) { a.hci_dev = iotjs_blehcisocket_devIdFor(blehcisocket, devId, false); a.hci_channel = HCI_CHANNEL_USER; - _this->_devId = a.hci_dev; - _this->_mode = HCI_CHANNEL_USER; + blehcisocket->_devId = a.hci_dev; + blehcisocket->_mode = HCI_CHANNEL_USER; - if (bind(_this->_socket, (struct sockaddr*)&a, sizeof(a)) < 0) { + if (bind(blehcisocket->_socket, (struct sockaddr*)&a, sizeof(a)) < 0) { DLOG("ERROR on binding: %s", strerror(errno)); } - return _this->_devId; + return blehcisocket->_devId; } -void iotjs_blehcisocket_bindControl(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_blehcisocket_t, blehcisocket); - +void iotjs_blehcisocket_bindControl(iotjs_blehcisocket_t* blehcisocket) { struct sockaddr_hci a; memset(&a, 0, sizeof(a)); @@ -246,24 +231,22 @@ void iotjs_blehcisocket_bindControl(THIS) { a.hci_dev = HCI_DEV_NONE; a.hci_channel = HCI_CHANNEL_CONTROL; - _this->_mode = HCI_CHANNEL_CONTROL; + blehcisocket->_mode = HCI_CHANNEL_CONTROL; - if (bind(_this->_socket, (struct sockaddr*)&a, sizeof(a)) < 0) { + if (bind(blehcisocket->_socket, (struct sockaddr*)&a, sizeof(a)) < 0) { DLOG("ERROR on binding: %s", strerror(errno)); } } -bool iotjs_blehcisocket_isDevUp(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_blehcisocket_t, blehcisocket); - +bool iotjs_blehcisocket_isDevUp(iotjs_blehcisocket_t* blehcisocket) { struct hci_dev_info di; bool isUp = false; memset(&di, 0x00, sizeof(di)); - di.dev_id = _this->_devId; + di.dev_id = blehcisocket->_devId; - if (ioctl(_this->_socket, HCIGETDEVINFO, (void*)&di) > -1) { + if (ioctl(blehcisocket->_socket, HCIGETDEVINFO, (void*)&di) > -1) { isUp = (di.flags & (1 << HCI_UP)) != 0; } @@ -271,94 +254,84 @@ bool iotjs_blehcisocket_isDevUp(THIS) { } -void iotjs_blehcisocket_setFilter(THIS, char* data, size_t length) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_blehcisocket_t, blehcisocket); - - if (setsockopt(_this->_socket, SOL_HCI, HCI_FILTER, data, (socklen_t)length) < - 0) { +void iotjs_blehcisocket_setFilter(iotjs_blehcisocket_t* blehcisocket, + char* data, size_t length) { + if (setsockopt(blehcisocket->_socket, SOL_HCI, HCI_FILTER, data, + (socklen_t)length) < 0) { iotjs_blehcisocket_emitErrnoError(blehcisocket); } } -void iotjs_blehcisocket_poll(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_blehcisocket_t, blehcisocket); - +void iotjs_blehcisocket_poll(iotjs_blehcisocket_t* blehcisocket) { int length = 0; char data[1024]; - length = read(_this->_socket, data, sizeof(data)); + length = read(blehcisocket->_socket, data, sizeof(data)); if (length > 0) { - if (_this->_mode == HCI_CHANNEL_RAW) { + if (blehcisocket->_mode == HCI_CHANNEL_RAW) { if (iotjs_blehcisocket_kernelDisconnectWorkArounds(blehcisocket, length, data) < 0) { return; } } - iotjs_jval_t* jhcisocket = iotjs_jobjectwrap_jobject(&_this->jobjectwrap); - iotjs_jval_t jemit = iotjs_jval_get_property(jhcisocket, "emit"); - IOTJS_ASSERT(iotjs_jval_is_function(&jemit)); + jerry_value_t jhcisocket = blehcisocket->jobject; + jerry_value_t jemit = iotjs_jval_get_property(jhcisocket, "emit"); + IOTJS_ASSERT(jerry_value_is_function(jemit)); - iotjs_jargs_t jargs = iotjs_jargs_create(2); - iotjs_jval_t str = iotjs_jval_create_string_raw("data"); + jerry_value_t str = jerry_create_string((const jerry_char_t*)"data"); IOTJS_ASSERT(length >= 0); - iotjs_jval_t jbuf = iotjs_bufferwrap_create_buffer((size_t)length); - iotjs_bufferwrap_t* buf_wrap = iotjs_bufferwrap_from_jbuffer(&jbuf); + jerry_value_t jbuf = iotjs_bufferwrap_create_buffer((size_t)length); + iotjs_bufferwrap_t* buf_wrap = iotjs_bufferwrap_from_jbuffer(jbuf); iotjs_bufferwrap_copy(buf_wrap, data, (size_t)length); - iotjs_jargs_append_jval(&jargs, &str); - iotjs_jargs_append_jval(&jargs, &jbuf); - iotjs_jhelper_call_ok(&jemit, jhcisocket, &jargs); - - iotjs_jval_destroy(&str); - iotjs_jval_destroy(&jbuf); - iotjs_jargs_destroy(&jargs); - iotjs_jval_destroy(&jemit); + jerry_value_t jargs[2] = { str, jbuf }; + jerry_value_t jres = jerry_call_function(jemit, jhcisocket, jargs, 2); + IOTJS_ASSERT(!jerry_value_is_error(jres)); + + jerry_release_value(jres); + jerry_release_value(str); + jerry_release_value(jbuf); + jerry_release_value(jemit); } } -void iotjs_blehcisocket_stop(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_blehcisocket_t, blehcisocket); - - uv_poll_stop(&_this->_pollHandle); +void iotjs_blehcisocket_stop(iotjs_blehcisocket_t* blehcisocket) { + uv_poll_stop(&blehcisocket->_pollHandle); } -void iotjs_blehcisocket_write(THIS, char* data, size_t length) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_blehcisocket_t, blehcisocket); - - if (write(_this->_socket, data, length) < 0) { +void iotjs_blehcisocket_write(iotjs_blehcisocket_t* blehcisocket, char* data, + size_t length) { + if (write(blehcisocket->_socket, data, length) < 0) { iotjs_blehcisocket_emitErrnoError(blehcisocket); } } -void iotjs_blehcisocket_emitErrnoError(THIS) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_blehcisocket_t, blehcisocket); - - iotjs_jval_t* jhcisocket = iotjs_jobjectwrap_jobject(&_this->jobjectwrap); - iotjs_jval_t jemit = iotjs_jval_get_property(jhcisocket, "emit"); - IOTJS_ASSERT(iotjs_jval_is_function(&jemit)); +void iotjs_blehcisocket_emitErrnoError(iotjs_blehcisocket_t* blehcisocket) { + jerry_value_t jhcisocket = blehcisocket->jobject; + jerry_value_t jemit = iotjs_jval_get_property(jhcisocket, "emit"); + IOTJS_ASSERT(jerry_value_is_function(jemit)); - iotjs_jargs_t jargs = iotjs_jargs_create(2); - iotjs_jval_t str = iotjs_jval_create_string_raw("error"); - iotjs_jval_t jerror = iotjs_jval_create_error(strerror(errno)); - iotjs_jargs_append_jval(&jargs, &str); - iotjs_jargs_append_jval(&jargs, &jerror); - iotjs_jhelper_call_ok(&jemit, jhcisocket, &jargs); + jerry_value_t str = jerry_create_string((const jerry_char_t*)"error"); + jerry_value_t jerror = + iotjs_jval_create_error_without_error_flag(strerror(errno)); + jerry_value_t jargs[2] = { str, jerror }; + jerry_value_t jres = jerry_call_function(jemit, jhcisocket, jargs, 2); + IOTJS_ASSERT(!jerry_value_is_error(jres)); - iotjs_jval_destroy(&str); - iotjs_jval_destroy(&jerror); - iotjs_jargs_destroy(&jargs); - iotjs_jval_destroy(&jemit); + jerry_release_value(jres); + jerry_release_value(str); + jerry_release_value(jerror); + jerry_release_value(jemit); } -int iotjs_blehcisocket_devIdFor(THIS, int* pDevId, bool isUp) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_blehcisocket_t, blehcisocket); - +int iotjs_blehcisocket_devIdFor(iotjs_blehcisocket_t* blehcisocket, int* pDevId, + bool isUp) { int devId = 0; // default if (pDevId == NULL) { @@ -372,7 +345,7 @@ int iotjs_blehcisocket_devIdFor(THIS, int* pDevId, bool isUp) { dl->dev_num = HCI_MAX_DEV; - if (ioctl(_this->_socket, HCIGETDEVLIST, dl) > -1) { + if (ioctl(blehcisocket->_socket, HCIGETDEVLIST, dl) > -1) { for (int i = 0; i < dl->dev_num; i++, dr++) { bool devUp = dr->dev_opt & (1 << HCI_UP); bool match = isUp ? devUp : !devUp; @@ -393,10 +366,8 @@ int iotjs_blehcisocket_devIdFor(THIS, int* pDevId, bool isUp) { } -int iotjs_blehcisocket_kernelDisconnectWorkArounds(THIS, int length, - char* data) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_blehcisocket_t, blehcisocket); - +int iotjs_blehcisocket_kernelDisconnectWorkArounds( + iotjs_blehcisocket_t* blehcisocket, int length, char* data) { if (length == 22 && data[0] == 0x04 && data[1] == 0x3e && data[2] == 0x13 && data[3] == 0x01 && data[4] == 0x00) { int l2socket; @@ -422,8 +393,8 @@ int iotjs_blehcisocket_kernelDisconnectWorkArounds(THIS, int length, memset(&l2a, 0, sizeof(l2a)); l2a.l2_family = AF_BLUETOOTH; l2a.l2_cid = l2cid; - memcpy(&l2a.l2_bdaddr, _this->_address, sizeof(l2a.l2_bdaddr)); - l2a.l2_bdaddr_type = _this->_addressType; + memcpy(&l2a.l2_bdaddr, blehcisocket->_address, sizeof(l2a.l2_bdaddr)); + l2a.l2_bdaddr_type = blehcisocket->_addressType; if (bind(l2socket, (struct sockaddr*)&l2a, sizeof(l2a)) < 0) { DLOG("ERROR on binding: %s", strerror(errno)); @@ -443,27 +414,23 @@ int iotjs_blehcisocket_kernelDisconnectWorkArounds(THIS, int length, return -1; } - _this->_l2sockets[handle] = l2socket; - _this->_l2socketCount++; + blehcisocket->_l2sockets[handle] = l2socket; + blehcisocket->_l2socketCount++; } else if (length == 7 && data[0] == 0x04 && data[1] == 0x05 && data[2] == 0x04 && data[3] == 0x00) { unsigned short handle = *((unsigned short*)(&data[4])); - if (_this->_l2socketCount > 0) { - close(_this->_l2sockets[handle]); - _this->_l2socketCount--; + if (blehcisocket->_l2socketCount > 0) { + close(blehcisocket->_l2sockets[handle]); + blehcisocket->_l2socketCount--; } } return 0; } -#undef THIS - void iotjs_blehcisocket_poll_cb(uv_poll_t* handle, int status, int events) { iotjs_blehcisocket_t* blehcisocket = (iotjs_blehcisocket_t*)handle->data; iotjs_blehcisocket_poll(blehcisocket); } - -#endif /* IOTJS_MODULE_BLE_HCI_SOCKET_LINUX_GENERAL_INL_H */ diff --git a/src/platform/linux/iotjs_module_gpio-linux.c b/src/modules/linux/iotjs_module_gpio-linux.c similarity index 68% rename from src/platform/linux/iotjs_module_gpio-linux.c rename to src/modules/linux/iotjs_module_gpio-linux.c index 5071cf8e63..60f703e3cd 100644 --- a/src/platform/linux/iotjs_module_gpio-linux.c +++ b/src/modules/linux/iotjs_module_gpio-linux.c @@ -42,6 +42,11 @@ #define GPIO_PIN_BUFFER_SIZE DEVICE_IO_PIN_BUFFER_SIZE #define GPIO_VALUE_BUFFER_SIZE 10 +struct iotjs_gpio_platform_data_s { + int value_fd; + uv_thread_t thread; + uv_mutex_t mutex; +}; // Implementation used here are based on: // https://www.kernel.org/doc/Documentation/gpio/sysfs.txt @@ -52,35 +57,32 @@ static const char* gpio_edge_string[] = { "none", "rising", "falling", "both" }; static int gpio_get_value_fd(iotjs_gpio_t* gpio) { int fd; - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_gpio_t, gpio); - uv_mutex_lock(&_this->mutex); - fd = _this->value_fd; - uv_mutex_unlock(&_this->mutex); + uv_mutex_lock(&gpio->platform_data->mutex); + fd = gpio->platform_data->value_fd; + uv_mutex_unlock(&gpio->platform_data->mutex); return fd; } static void gpio_set_value_fd(iotjs_gpio_t* gpio, int fd) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_gpio_t, gpio); - - uv_mutex_lock(&_this->mutex); - _this->value_fd = fd; - uv_mutex_unlock(&_this->mutex); + uv_mutex_lock(&gpio->platform_data->mutex); + gpio->platform_data->value_fd = fd; + uv_mutex_unlock(&gpio->platform_data->mutex); } static void gpio_emit_change_event(iotjs_gpio_t* gpio) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_gpio_t, gpio); - - iotjs_jval_t* jgpio = iotjs_jobjectwrap_jobject(&_this->jobjectwrap); - iotjs_jval_t jonChange = iotjs_jval_get_property(jgpio, "onChange"); - IOTJS_ASSERT(iotjs_jval_is_function(&jonChange)); + jerry_value_t jgpio = gpio->jobject; + jerry_value_t jonChange = iotjs_jval_get_property(jgpio, "onChange"); + IOTJS_ASSERT(jerry_value_is_function(jonChange)); - iotjs_jhelper_call_ok(&jonChange, jgpio, iotjs_jargs_get_empty()); + jerry_value_t jres = jerry_call_function(jonChange, jgpio, NULL, 0); + IOTJS_ASSERT(!jerry_value_is_error(jres)); - iotjs_jval_destroy(&jonChange); + jerry_release_value(jres); + jerry_release_value(jonChange); } @@ -166,27 +168,25 @@ static bool gpio_set_mode(uint32_t pin, GpioMode mode) { static bool gpio_set_edge(iotjs_gpio_t* gpio) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_gpio_t, gpio); - char edge_path[GPIO_PATH_BUFFER_SIZE]; - snprintf(edge_path, GPIO_PATH_BUFFER_SIZE, GPIO_PIN_FORMAT_EDGE, _this->pin); - iotjs_systemio_open_write_close(edge_path, gpio_edge_string[_this->edge]); + snprintf(edge_path, GPIO_PATH_BUFFER_SIZE, GPIO_PIN_FORMAT_EDGE, gpio->pin); + iotjs_systemio_open_write_close(edge_path, gpio_edge_string[gpio->edge]); - if (_this->direction == kGpioDirectionIn && _this->edge != kGpioEdgeNone) { + if (gpio->direction == kGpioDirectionIn && gpio->edge != kGpioEdgeNone) { char value_path[GPIO_PATH_BUFFER_SIZE]; snprintf(value_path, GPIO_PATH_BUFFER_SIZE, GPIO_PIN_FORMAT_VALUE, - _this->pin); - if ((_this->value_fd = open(value_path, O_RDONLY)) < 0) { + gpio->pin); + if ((gpio->platform_data->value_fd = open(value_path, O_RDONLY)) < 0) { DLOG("GPIO Error in open"); return false; } - uv_mutex_init(&_this->mutex); // Create edge detection thread // When the GPIO pin is closed, thread is terminated. - if (uv_thread_create(&_this->thread, gpio_edge_detection_cb, (void*)gpio) < - 0) { + int ret = uv_thread_create(&gpio->platform_data->thread, + gpio_edge_detection_cb, (void*)gpio); + if (ret < 0) { DLOG("GPIO Error in uv_thread_create"); } return false; @@ -196,89 +196,98 @@ static bool gpio_set_edge(iotjs_gpio_t* gpio) { } -bool iotjs_gpio_write(iotjs_gpio_t* gpio, bool value) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_gpio_t, gpio); +void iotjs_gpio_create_platform_data(iotjs_gpio_t* gpio) { + gpio->platform_data = IOTJS_ALLOC(iotjs_gpio_platform_data_t); + gpio->platform_data->value_fd = -1; + uv_mutex_init(&gpio->platform_data->mutex); +} + + +void iotjs_gpio_destroy_platform_data( + iotjs_gpio_platform_data_t* platform_data) { + IOTJS_RELEASE(platform_data); +} + +bool iotjs_gpio_write(iotjs_gpio_t* gpio) { char value_path[GPIO_PATH_BUFFER_SIZE]; - snprintf(value_path, GPIO_PATH_BUFFER_SIZE, GPIO_PIN_FORMAT_VALUE, - _this->pin); + snprintf(value_path, GPIO_PATH_BUFFER_SIZE, GPIO_PIN_FORMAT_VALUE, gpio->pin); - const char* buffer = value ? "1" : "0"; + const char* buffer = gpio->value ? "1" : "0"; - DDDLOG("%s - pin: %d, value: %d", __func__, _this->pin, value); + DDDLOG("%s - pin: %d, value: %d", __func__, gpio->pin, gpio->value); return iotjs_systemio_open_write_close(value_path, buffer); } -int iotjs_gpio_read(iotjs_gpio_t* gpio) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_gpio_t, gpio); - +bool iotjs_gpio_read(iotjs_gpio_t* gpio) { char buffer[GPIO_VALUE_BUFFER_SIZE]; char value_path[GPIO_PATH_BUFFER_SIZE]; - snprintf(value_path, GPIO_PATH_BUFFER_SIZE, GPIO_PIN_FORMAT_VALUE, - _this->pin); + snprintf(value_path, GPIO_PATH_BUFFER_SIZE, GPIO_PIN_FORMAT_VALUE, gpio->pin); if (!iotjs_systemio_open_read_close(value_path, buffer, GPIO_VALUE_BUFFER_SIZE - 1)) { - return -1; + return false; } - return atoi(buffer); + gpio->value = atoi(buffer) != 0; + + return true; } bool iotjs_gpio_close(iotjs_gpio_t* gpio) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_gpio_t, gpio); - char buff[GPIO_PIN_BUFFER_SIZE]; - snprintf(buff, GPIO_PIN_BUFFER_SIZE, "%d", _this->pin); + snprintf(buff, GPIO_PIN_BUFFER_SIZE, "%d", gpio->pin); gpio_set_value_fd(gpio, -1); - close(_this->value_fd); + close(gpio->platform_data->value_fd); return iotjs_systemio_open_write_close(GPIO_PIN_FORMAT_UNEXPORT, buff); } -void iotjs_gpio_open_worker(uv_work_t* work_req) { - GPIO_WORKER_INIT; - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_gpio_t, gpio); - - DDDLOG("%s - pin: %d, dir: %d, mode: %d", __func__, _this->pin, - _this->direction, _this->mode); +bool iotjs_gpio_open(iotjs_gpio_t* gpio) { + DDDLOG("%s - pin: %d, dir: %d, mode: %d", __func__, gpio->pin, + gpio->direction, gpio->mode); // Open GPIO pin. char exported_path[GPIO_PATH_BUFFER_SIZE]; - snprintf(exported_path, GPIO_PATH_BUFFER_SIZE, GPIO_PIN_FORMAT, _this->pin); + snprintf(exported_path, GPIO_PATH_BUFFER_SIZE, GPIO_PIN_FORMAT, gpio->pin); const char* created_files[] = { GPIO_DIRECTION, GPIO_EDGE, GPIO_VALUE }; int created_files_length = sizeof(created_files) / sizeof(created_files[0]); - if (!iotjs_systemio_device_open(GPIO_PIN_FORMAT_EXPORT, _this->pin, + if (!iotjs_systemio_device_open(GPIO_PIN_FORMAT_EXPORT, gpio->pin, exported_path, created_files, created_files_length)) { - req_data->result = false; - return; + return false; } // Set direction. - if (!gpio_set_direction(_this->pin, _this->direction)) { - req_data->result = false; - return; + if (!gpio_set_direction(gpio->pin, gpio->direction)) { + return false; } // Set mode. - if (!gpio_set_mode(_this->pin, _this->mode)) { - req_data->result = false; - return; + if (!gpio_set_mode(gpio->pin, gpio->mode)) { + return false; } - // Set edge + // Set edge. if (!gpio_set_edge(gpio)) { - req_data->result = false; - return; + return false; } - req_data->result = true; + return true; +} + + +bool iotjs_gpio_set_direction(iotjs_gpio_t* gpio) { + if (!gpio_set_direction(gpio->pin, gpio->direction)) { + DLOG("%s, Cannot set direction.", __func__); + return false; + } + return true; } diff --git a/src/modules/linux/iotjs_module_i2c-linux.c b/src/modules/linux/iotjs_module_i2c-linux.c new file mode 100644 index 0000000000..987d318700 --- /dev/null +++ b/src/modules/linux/iotjs_module_i2c-linux.c @@ -0,0 +1,150 @@ +/* The MIT License (MIT) + * + * Copyright (c) 2005-2014 RoadNarrows LLC. + * http://roadnarrows.com + * All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/* Copyright 2016-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. + */ + + +/* Some functions are modified from the RoadNarrows-robotics i2c library. + * (distributed under the MIT license.) + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "modules/iotjs_module_i2c.h" + + +#define I2C_SLAVE_FORCE 0x0706 + +struct iotjs_i2c_platform_data_s { + iotjs_string_t device; + int device_fd; + uint8_t addr; +}; + +void iotjs_i2c_create_platform_data(iotjs_i2c_t* i2c) { + i2c->platform_data = IOTJS_ALLOC(iotjs_i2c_platform_data_t); + i2c->platform_data->device_fd = -1; +} + +void iotjs_i2c_destroy_platform_data(iotjs_i2c_platform_data_t* pdata) { + iotjs_string_destroy(&pdata->device); + IOTJS_RELEASE(pdata); +} + +jerry_value_t iotjs_i2c_set_platform_config(iotjs_i2c_t* i2c, + const jerry_value_t jconfig) { + iotjs_i2c_platform_data_t* platform_data = i2c->platform_data; + + JS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->device, + IOTJS_MAGIC_STRING_DEVICE, string); + + return jerry_create_undefined(); +} + + +#define I2C_METHOD_HEADER(arg) \ + iotjs_i2c_platform_data_t* platform_data = arg->platform_data; \ + IOTJS_ASSERT(platform_data); \ + if (platform_data->device_fd < 0) { \ + DLOG("%s: I2C is not opened", __func__); \ + return false; \ + } + +bool iotjs_i2c_open(iotjs_i2c_t* i2c) { + iotjs_i2c_platform_data_t* platform_data = i2c->platform_data; + + platform_data->device_fd = + open(iotjs_string_data(&platform_data->device), O_RDWR); + + if (platform_data->device_fd == -1) { + DLOG("%s : cannot open", __func__); + return false; + } + + if (ioctl(platform_data->device_fd, I2C_SLAVE_FORCE, i2c->address) < 0) { + DLOG("%s : cannot set address", __func__); + return false; + } + + return true; +} + +bool iotjs_i2c_close(iotjs_i2c_t* i2c) { + I2C_METHOD_HEADER(i2c); + + if (close(platform_data->device_fd) < 0) { + DLOG("%s : cannot close", __func__); + return false; + } + + platform_data->device_fd = -1; + + return true; +} + +bool iotjs_i2c_write(iotjs_i2c_t* i2c) { + I2C_METHOD_HEADER(i2c); + + uint8_t len = i2c->buf_len; + char* data = i2c->buf_data; + + int ret = write(platform_data->device_fd, data, len); + + IOTJS_RELEASE(i2c->buf_data); + + return ret == len; +} + +bool iotjs_i2c_read(iotjs_i2c_t* i2c) { + I2C_METHOD_HEADER(i2c); + + uint8_t len = i2c->buf_len; + i2c->buf_data = iotjs_buffer_allocate(len); + + return read(platform_data->device_fd, i2c->buf_data, len) == len; +} diff --git a/src/platform/linux/iotjs_module_pwm-linux.c b/src/modules/linux/iotjs_module_pwm-linux.c similarity index 58% rename from src/platform/linux/iotjs_module_pwm-linux.c rename to src/modules/linux/iotjs_module_pwm-linux.c index e2d72b93f7..51f0888b92 100644 --- a/src/platform/linux/iotjs_module_pwm-linux.c +++ b/src/modules/linux/iotjs_module_pwm-linux.c @@ -13,10 +13,6 @@ * limitations under the License. */ -#ifndef IOTJS_MODULE_PWM_LINUX_GENERAL_INL_H -#define IOTJS_MODULE_PWM_LINUX_GENERAL_INL_H - - #include #include #include @@ -41,6 +37,41 @@ #define PWM_PATH_BUFFER_SIZE 64 #define PWM_VALUE_BUFFER_SIZE 32 +struct iotjs_pwm_platform_data_s { + int chip; + iotjs_string_t device; +}; + +void iotjs_pwm_create_platform_data(iotjs_pwm_t* pwm) { + pwm->platform_data = IOTJS_ALLOC(iotjs_pwm_platform_data_t); + pwm->platform_data->chip = 0; +} + +void iotjs_pwm_destroy_platform_data(iotjs_pwm_platform_data_t* pdata) { + iotjs_string_destroy(&pdata->device); + IOTJS_RELEASE(pdata); +} + +jerry_value_t iotjs_pwm_set_platform_config(iotjs_pwm_t* pwm, + const jerry_value_t jconfig) { + iotjs_pwm_platform_data_t* platform_data = pwm->platform_data; + jerry_value_t jchip = + iotjs_jval_get_property(jconfig, IOTJS_MAGIC_STRING_CHIP); + + if (jerry_value_is_error(jchip)) { + return jchip; + } + + if (jerry_value_is_number(jchip)) { + platform_data->chip = iotjs_jval_as_number(jchip); + } else { + platform_data->chip = 0; + } + + jerry_release_value(jchip); + + return jerry_create_undefined(); +} // Generate device path for specified PWM device. // The path may include node suffix if passed ('enable', 'period', 'duty_cycle') @@ -77,70 +108,67 @@ static double adjust_period(double period) { } -void iotjs_pwm_open_worker(uv_work_t* work_req) { - PWM_WORKER_INIT; - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_t, pwm); +bool iotjs_pwm_open(iotjs_pwm_t* pwm) { + iotjs_pwm_platform_data_t* platform_data = pwm->platform_data; char path[PWM_PATH_BUFFER_SIZE] = { 0 }; - if (snprintf(path, PWM_PATH_BUFFER_SIZE, PWM_PIN_FORMAT, _this->chip, - _this->pin) < 0) { - req_data->result = false; - return; + if (snprintf(path, PWM_PATH_BUFFER_SIZE, PWM_PIN_FORMAT, platform_data->chip, + pwm->pin) < 0) { + return false; } - _this->device = iotjs_string_create_with_size(path, strlen(path)); + platform_data->device = iotjs_string_create_with_size(path, strlen(path)); // See if the PWM is already opened. if (!iotjs_systemio_check_path(path)) { // Write exporting PWM path char export_path[PWM_PATH_BUFFER_SIZE] = { 0 }; - snprintf(export_path, PWM_PATH_BUFFER_SIZE, PWM_EXPORT, _this->chip); + snprintf(export_path, PWM_PATH_BUFFER_SIZE, PWM_EXPORT, + platform_data->chip); const char* created_files[] = { PWM_PIN_DUTYCYCLE, PWM_PIN_PERIOD, PWM_PIN_ENABlE }; int created_files_length = sizeof(created_files) / sizeof(created_files[0]); - if (!iotjs_systemio_device_open(export_path, _this->pin, path, - created_files, created_files_length)) { - req_data->result = false; - return; + if (!iotjs_systemio_device_open(export_path, pwm->pin, path, created_files, + created_files_length)) { + return false; } } // Set options. - if (_this->period >= 0) { + if (pwm->period >= 0) { if (!iotjs_pwm_set_period(pwm)) { - req_data->result = false; - return; + return false; } - if (_this->duty_cycle >= 0) { + if (pwm->duty_cycle >= 0) { if (!iotjs_pwm_set_dutycycle(pwm)) { - req_data->result = false; - return; + return false; } } } DDDLOG("%s - path: %s", __func__, path); - req_data->result = true; + return true; } bool iotjs_pwm_set_period(iotjs_pwm_t* pwm) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_t, pwm); + iotjs_pwm_platform_data_t* platform_data = pwm->platform_data; bool result = false; - if (isfinite(_this->period) && _this->period >= 0.0) { - char* devicePath = generate_device_subpath(&_this->device, PWM_PIN_PERIOD); + if (isfinite(pwm->period) && pwm->period >= 0.0) { + char* devicePath = + generate_device_subpath(&platform_data->device, PWM_PIN_PERIOD); if (devicePath) { // Linux API uses nanoseconds, thus 1E9 - unsigned int value = (unsigned)(adjust_period(_this->period) * 1.E9); - DDLOG("%s - path: %s, value: %fs", __func__, devicePath, 1.E-9 * value); + unsigned int value = (unsigned)(adjust_period(pwm->period) * 1.E9); + DDDLOG("%s - path: %s, value: %fs", __func__, devicePath, 1.E-9 * value); char buf[PWM_VALUE_BUFFER_SIZE]; if (snprintf(buf, sizeof(buf), "%d", value) > 0) { result = iotjs_systemio_open_write_close(devicePath, buf); } - free(devicePath); + IOTJS_RELEASE(devicePath); } } return result; @@ -148,27 +176,28 @@ bool iotjs_pwm_set_period(iotjs_pwm_t* pwm) { bool iotjs_pwm_set_dutycycle(iotjs_pwm_t* pwm) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_t, pwm); + iotjs_pwm_platform_data_t* platform_data = pwm->platform_data; bool result = false; - double dutyCycle = _this->duty_cycle; - if (isfinite(_this->period) && _this->period >= 0.0 && isfinite(dutyCycle) && + double dutyCycle = pwm->duty_cycle; + if (isfinite(pwm->period) && pwm->period >= 0.0 && isfinite(dutyCycle) && 0.0 <= dutyCycle && dutyCycle <= 1.0) { char* devicePath = - generate_device_subpath(&_this->device, PWM_PIN_DUTYCYCLE); + generate_device_subpath(&platform_data->device, PWM_PIN_DUTYCYCLE); if (devicePath) { - double period = adjust_period(_this->period); + double period = adjust_period(pwm->period); // Linux API uses nanoseconds, thus 1E9 - unsigned dutyCycleValue = (unsigned)(period * _this->duty_cycle * 1E9); + unsigned dutyCycleValue = (unsigned)(period * pwm->duty_cycle * 1E9); - DDLOG("%s - path: %s, value: %d\n", __func__, devicePath, dutyCycleValue); + DDDLOG("%s - path: %s, value: %d\n", __func__, devicePath, + dutyCycleValue); char buf[PWM_VALUE_BUFFER_SIZE]; if (snprintf(buf, sizeof(buf), "%d", dutyCycleValue) < 0) { return false; } result = iotjs_systemio_open_write_close(devicePath, buf); - free(devicePath); + IOTJS_RELEASE(devicePath); } } return result; @@ -176,36 +205,36 @@ bool iotjs_pwm_set_dutycycle(iotjs_pwm_t* pwm) { bool iotjs_pwm_set_enable(iotjs_pwm_t* pwm) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_t, pwm); + iotjs_pwm_platform_data_t* platform_data = pwm->platform_data; bool result = false; - - char* devicePath = generate_device_subpath(&_this->device, PWM_PIN_ENABlE); + char* devicePath = + generate_device_subpath(&platform_data->device, PWM_PIN_ENABlE); if (devicePath) { char value[4]; - if (snprintf(value, sizeof(value), "%d", _this->enable) < 0) { + if (snprintf(value, sizeof(value), "%d", pwm->enable) < 0) { return false; } - DDLOG("%s - path: %s, set: %d\n", __func__, devicePath, _this->enable); + DDDLOG("%s - path: %s, set: %d\n", __func__, devicePath, pwm->enable); char buf[PWM_VALUE_BUFFER_SIZE]; - if (snprintf(buf, sizeof(buf), "%d", _this->enable) < 0) { + if (snprintf(buf, sizeof(buf), "%d", pwm->enable) < 0) { return false; } result = iotjs_systemio_open_write_close(devicePath, buf); - free(devicePath); + IOTJS_RELEASE(devicePath); } return result; } bool iotjs_pwm_close(iotjs_pwm_t* pwm) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_t, pwm); + iotjs_pwm_platform_data_t* platform_data = pwm->platform_data; char path[PWM_PATH_BUFFER_SIZE] = { 0 }; - if (snprintf(path, PWM_PATH_BUFFER_SIZE, PWM_PIN_FORMAT, _this->chip, - _this->pin) < 0) { + if (snprintf(path, PWM_PATH_BUFFER_SIZE, PWM_PIN_FORMAT, platform_data->chip, + pwm->pin) < 0) { return false; } @@ -213,17 +242,14 @@ bool iotjs_pwm_close(iotjs_pwm_t* pwm) { // Write exporting pin path char unexport_path[PWM_PATH_BUFFER_SIZE] = { 0 }; if (snprintf(unexport_path, PWM_PATH_BUFFER_SIZE, PWM_UNEXPORT, - _this->chip) < 0) { + platform_data->chip) < 0) { return false; } - iotjs_systemio_device_close(unexport_path, _this->pin); + iotjs_systemio_device_close(unexport_path, pwm->pin); } DDDLOG("%s- path: %s", __func__, path); return true; } - - -#endif /* IOTJS_MODULE_PWM_LINUX_GENERAL_INL_H */ diff --git a/src/modules/linux/iotjs_module_spi-linux.c b/src/modules/linux/iotjs_module_spi-linux.c new file mode 100644 index 0000000000..9cede21e91 --- /dev/null +++ b/src/modules/linux/iotjs_module_spi-linux.c @@ -0,0 +1,180 @@ +/* Copyright 2016-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 +#include +#include + +#include "iotjs_def.h" +#include "iotjs_systemio-linux.h" +#include "modules/iotjs_module_buffer.h" +#include "modules/iotjs_module_spi.h" + +#define ADC_DEVICE_PATH_FORMAT "/dev/spidev%d.%d" +#define ADC_DEVICE_PATH_BUFFER_SIZE 16 + +struct iotjs_spi_platform_data_s { + iotjs_string_t device; + int device_fd; +}; + +void iotjs_spi_create_platform_data(iotjs_spi_t* spi) { + spi->platform_data = IOTJS_ALLOC(iotjs_spi_platform_data_t); + spi->platform_data->device_fd = -1; +} + +void iotjs_spi_destroy_platform_data(iotjs_spi_platform_data_t* pdata) { + iotjs_string_destroy(&pdata->device); + IOTJS_RELEASE(pdata); +} + +jerry_value_t iotjs_spi_set_platform_config(iotjs_spi_t* spi, + const jerry_value_t jconfig) { + iotjs_spi_platform_data_t* platform_data = spi->platform_data; + + JS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->device, + IOTJS_MAGIC_STRING_DEVICE, string); + + return jerry_create_undefined(); +} + +static bool spi_set_configuration(iotjs_spi_t* spi) { + int fd = spi->platform_data->device_fd; + if (fd < 0) { + return false; + } + + uint8_t data; + + switch (spi->mode) { + case kSpiMode_0: + data = SPI_MODE_0; + break; + case kSpiMode_1: + data = SPI_MODE_1; + break; + case kSpiMode_2: + data = SPI_MODE_2; + break; + case kSpiMode_3: + data = SPI_MODE_3; + break; + default: + data = SPI_MODE_0; + } + if (spi->loopback) { + data |= SPI_LOOP; + } + + if (spi->chip_select == kSpiCsHigh) { + data |= SPI_CS_HIGH; + } + + if (ioctl(fd, SPI_IOC_WR_MODE, &spi->mode) < 0) { + return false; + } + + + if (spi->bit_order == kSpiOrderLsb) { + data = 1; + if (ioctl(fd, SPI_IOC_WR_LSB_FIRST, &data) < 0) { + return false; + } + } + + if (ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &spi->bits_per_word) < 0) { + return false; + } + + if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi->max_speed) < 0) { + return false; + } + + DDDLOG( + "SPI Options \n mode: %d\n chipSelect: %d\n bitOrder: %d\n " + "maxSpeed: %d\n bitPerWord: %d\n loopback: %d", + spi->mode, spi->chip_select, spi->bit_order, spi->max_speed, + spi->bits_per_word, spi->loopback); + + return true; +} + +bool iotjs_spi_transfer(iotjs_spi_t* spi) { + iotjs_spi_platform_data_t* platform_data = spi->platform_data; + + struct spi_ioc_transfer data = {.tx_buf = (unsigned long)spi->tx_buf_data, + .rx_buf = (unsigned long)spi->rx_buf_data, + .len = spi->buf_len, + .speed_hz = spi->max_speed, + .bits_per_word = spi->bits_per_word, + .delay_usecs = 0 }; + + // Transfer data + int err = ioctl(platform_data->device_fd, SPI_IOC_MESSAGE(1), &data); + if (err < 1) { + DLOG("%s - transfer failed: %d", __func__, err); + return false; + } + + return true; +} + +bool iotjs_spi_close(iotjs_spi_t* spi) { + iotjs_spi_platform_data_t* platform_data = spi->platform_data; + + if (platform_data->device_fd >= 0) { + const iotjs_environment_t* env = iotjs_environment_get(); + uv_loop_t* loop = iotjs_environment_loop(env); + uv_fs_t fs_close_req; + + int err = uv_fs_close(loop, &fs_close_req, platform_data->device_fd, NULL); + uv_fs_req_cleanup(&fs_close_req); + if (err < 0) { + DLOG("%s - close failed: %d", __func__, err); + return false; + } + platform_data->device_fd = -1; + } + + return true; +} + + +bool iotjs_spi_open(iotjs_spi_t* spi) { + iotjs_spi_platform_data_t* platform_data = spi->platform_data; + + const char* device_path = iotjs_string_data(&platform_data->device); + if (!iotjs_systemio_check_path(device_path)) { + return false; + } + + // Open file + const iotjs_environment_t* env = iotjs_environment_get(); + uv_loop_t* loop = iotjs_environment_loop(env); + + uv_fs_t open_req; + int result = uv_fs_open(loop, &open_req, device_path, O_RDONLY, 0666, NULL); + uv_fs_req_cleanup(&open_req); + if (result < 0) { + return false; + } + platform_data->device_fd = open_req.result; + + // Set options + if (!spi_set_configuration(spi)) { + return false; + } + return true; +} diff --git a/src/platform/linux/iotjs_module_uart-linux.c b/src/modules/linux/iotjs_module_uart-linux.c similarity index 53% rename from src/platform/linux/iotjs_module_uart-linux.c rename to src/modules/linux/iotjs_module_uart-linux.c index 714e17583c..52fc13871d 100644 --- a/src/platform/linux/iotjs_module_uart-linux.c +++ b/src/modules/linux/iotjs_module_uart-linux.c @@ -13,21 +13,20 @@ * limitations under the License. */ - -#ifndef IOTJS_MODULE_UART_LINUX_GENERAL_INL_H -#define IOTJS_MODULE_UART_LINUX_GENERAL_INL_H - #include #include #include #include +#include "iotjs_uv_handle.h" #include "modules/iotjs_module_uart.h" -static int baud_to_constant(int baudRate) { +struct iotjs_uart_platform_data_s { + iotjs_string_t device_path; +}; + +static unsigned baud_to_constant(unsigned baudRate) { switch (baudRate) { - case 0: - return B0; case 50: return B50; case 75: @@ -65,10 +64,9 @@ static int baud_to_constant(int baudRate) { case 230400: return B230400; } - return -1; + return B0; } - static int databits_to_constant(int dataBits) { switch (dataBits) { case 8: @@ -83,56 +81,69 @@ static int databits_to_constant(int dataBits) { return -1; } +void iotjs_uart_create_platform_data(iotjs_uart_t* uart) { + uart->platform_data = IOTJS_ALLOC(iotjs_uart_platform_data_t); +} + +void iotjs_uart_destroy_platform_data( + iotjs_uart_platform_data_t* platform_data) { + IOTJS_ASSERT(platform_data); + + iotjs_string_destroy(&platform_data->device_path); + IOTJS_RELEASE(platform_data); +} + +jerry_value_t iotjs_uart_set_platform_config(iotjs_uart_t* uart, + const jerry_value_t jconfig) { + JS_GET_REQUIRED_CONF_VALUE(jconfig, uart->platform_data->device_path, + IOTJS_MAGIC_STRING_DEVICE, string); -void iotjs_uart_open_worker(uv_work_t* work_req) { - UART_WORKER_INIT; - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_uart_t, uart); + return jerry_create_undefined(); +} - int fd = open(iotjs_string_data(&_this->device_path), +bool iotjs_uart_open(uv_handle_t* uart_poll_handle) { + iotjs_uart_t* uart = + (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle); + int fd = open(iotjs_string_data(&uart->platform_data->device_path), O_RDWR | O_NOCTTY | O_NDELAY); if (fd < 0) { - req_data->result = false; - return; + return false; } struct termios options; tcgetattr(fd, &options); options.c_cflag = CLOCAL | CREAD; - options.c_cflag |= (tcflag_t)baud_to_constant(_this->baud_rate); - options.c_cflag |= (tcflag_t)databits_to_constant(_this->data_bits); + options.c_cflag |= (tcflag_t)baud_to_constant(uart->baud_rate); + options.c_cflag |= (tcflag_t)databits_to_constant(uart->data_bits); options.c_iflag = IGNPAR; options.c_oflag = 0; options.c_lflag = 0; tcflush(fd, TCIFLUSH); tcsetattr(fd, TCSANOW, &options); - _this->device_fd = fd; - uv_poll_t* poll_handle = &_this->poll_handle; + uart->device_fd = fd; + iotjs_uart_register_read_cb((uv_poll_t*)uart_poll_handle); - uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get()); - uv_poll_init(loop, poll_handle, fd); - poll_handle->data = uart; - uv_poll_start(poll_handle, UV_READABLE, iotjs_uart_read_cb); - - req_data->result = true; + return true; } +bool iotjs_uart_write(uv_handle_t* uart_poll_handle) { + iotjs_uart_t* uart = + (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle); -bool iotjs_uart_write(iotjs_uart_t* uart) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_uart_t, uart); int bytesWritten = 0; unsigned offset = 0; - int fd = _this->device_fd; - const char* buf_data = iotjs_string_data(&_this->buf_data); + int fd = uart->device_fd; + const char* buf_data = iotjs_string_data(&uart->buf_data); DDDLOG("%s - data: %s", __func__, buf_data); do { errno = 0; - bytesWritten = write(fd, buf_data + offset, _this->buf_len - offset); + bytesWritten = write(fd, buf_data + offset, uart->buf_len - offset); tcdrain(fd); - DDDLOG("%s - size: %d", __func__, _this->buf_len - offset); + DDDLOG("%s - size: %d", __func__, uart->buf_len - offset); if (bytesWritten != -1) { offset += (unsigned)bytesWritten; @@ -145,10 +156,17 @@ bool iotjs_uart_write(iotjs_uart_t* uart) { return false; - } while (_this->buf_len > offset); + } while (uart->buf_len > offset); return true; } +void iotjs_uart_handle_close_cb(uv_handle_t* uart_poll_handle) { + iotjs_uart_t* uart = + (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle); -#endif /* IOTJS_MODULE_UART_LINUX_GENERAL_INL_H */ + if (close(uart->device_fd) < 0) { + DLOG(iotjs_periph_error_str(kUartOpClose)); + IOTJS_ASSERT(0); + } +} diff --git a/src/modules/mock/iotjs_module_gpio-mock.c b/src/modules/mock/iotjs_module_gpio-mock.c new file mode 100644 index 0000000000..04db0a88f6 --- /dev/null +++ b/src/modules/mock/iotjs_module_gpio-mock.c @@ -0,0 +1,73 @@ +/* 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 + +#include "modules/iotjs_module_gpio.h" + +struct iotjs_gpio_platform_data_s { + bool is_open; + bool level; +}; + + +void iotjs_gpio_create_platform_data(iotjs_gpio_t* gpio) { + gpio->platform_data = IOTJS_ALLOC(iotjs_gpio_platform_data_t); +} + + +void iotjs_gpio_destroy_platform_data( + iotjs_gpio_platform_data_t* platform_data) { + IOTJS_RELEASE(platform_data); +} + + +bool iotjs_gpio_open(iotjs_gpio_t* gpio) { + DDDLOG("%s - pin: %d, direction: %d, mode: %d", __func__, gpio->pin, + gpio->direction, gpio->mode); + if (gpio->platform_data->is_open) { + return false; // pin is open already + } + + gpio->platform_data->is_open = true; + return true; +} + + +bool iotjs_gpio_write(iotjs_gpio_t* gpio) { + gpio->platform_data->level = gpio->value; + return true; +} + + +bool iotjs_gpio_read(iotjs_gpio_t* gpio) { + gpio->value = gpio->platform_data->level; + return true; +} + + +bool iotjs_gpio_close(iotjs_gpio_t* gpio) { + if (!gpio->platform_data->is_open) { + return false; // pin is not open + } + + gpio->platform_data->is_open = false; + return true; +} + + +bool iotjs_gpio_set_direction(iotjs_gpio_t* gpio) { + return true; +} diff --git a/src/modules/mock/iotjs_module_i2c-mock.c b/src/modules/mock/iotjs_module_i2c-mock.c new file mode 100644 index 0000000000..f18af80333 --- /dev/null +++ b/src/modules/mock/iotjs_module_i2c-mock.c @@ -0,0 +1,54 @@ +/* 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 "modules/iotjs_module_i2c.h" + +struct iotjs_i2c_platform_data_s { + int bus; +}; + + +void iotjs_i2c_create_platform_data(iotjs_i2c_t* i2c) { + i2c->platform_data = IOTJS_ALLOC(iotjs_i2c_platform_data_t); +} + + +void iotjs_i2c_destroy_platform_data(iotjs_i2c_platform_data_t* platform_data) { + IOTJS_ASSERT(platform_data); + IOTJS_RELEASE(platform_data); +} + +jerry_value_t iotjs_i2c_set_platform_config(iotjs_i2c_t* i2c, + const jerry_value_t jconfig) { + return jerry_create_undefined(); +} + +bool iotjs_i2c_open(iotjs_i2c_t* i2c) { + return true; +} + +bool iotjs_i2c_close(iotjs_i2c_t* i2c) { + return true; +} + +bool iotjs_i2c_write(iotjs_i2c_t* i2c) { + IOTJS_RELEASE(i2c->buf_data); + return true; +} + +bool iotjs_i2c_read(iotjs_i2c_t* i2c) { + i2c->buf_data = iotjs_buffer_allocate(i2c->buf_len); + return true; +} diff --git a/src/modules/mock/iotjs_module_pwm-mock.c b/src/modules/mock/iotjs_module_pwm-mock.c new file mode 100644 index 0000000000..0b1a3e12a3 --- /dev/null +++ b/src/modules/mock/iotjs_module_pwm-mock.c @@ -0,0 +1,81 @@ +/* Copyright 2019-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 "modules/iotjs_module_pwm.h" + +struct iotjs_pwm_platform_data_s { + bool is_open; +}; + +void iotjs_pwm_create_platform_data(iotjs_pwm_t* pwm) { + pwm->platform_data = IOTJS_ALLOC(iotjs_pwm_platform_data_t); +} + +void iotjs_pwm_destroy_platform_data(iotjs_pwm_platform_data_t* pdata) { + IOTJS_RELEASE(pdata); +} + +jerry_value_t iotjs_pwm_set_platform_config(iotjs_pwm_t* pwm, + const jerry_value_t jconfig) { + IOTJS_UNUSED(pwm); + IOTJS_UNUSED(jconfig); + if (jerry_value_is_object(jconfig)) { + return jerry_create_undefined(); + } else { + return JS_CREATE_ERROR(COMMON, "Config must be an object."); + } +} + +bool iotjs_pwm_open(iotjs_pwm_t* pwm) { + iotjs_pwm_platform_data_t* platform_data = pwm->platform_data; + IOTJS_ASSERT(platform_data != NULL); + + if (platform_data->is_open) { + return false; // pin is open already + } + + platform_data->is_open = true; + return true; +} + +bool iotjs_pwm_set_period(iotjs_pwm_t* pwm) { + iotjs_pwm_platform_data_t* platform_data = pwm->platform_data; + IOTJS_ASSERT(platform_data != NULL); + return true; +} + +bool iotjs_pwm_set_dutycycle(iotjs_pwm_t* pwm) { + iotjs_pwm_platform_data_t* platform_data = pwm->platform_data; + IOTJS_ASSERT(platform_data != NULL); + return true; +} + +bool iotjs_pwm_set_enable(iotjs_pwm_t* pwm) { + iotjs_pwm_platform_data_t* platform_data = pwm->platform_data; + IOTJS_ASSERT(platform_data != NULL); + return true; +} + +bool iotjs_pwm_close(iotjs_pwm_t* pwm) { + iotjs_pwm_platform_data_t* platform_data = pwm->platform_data; + IOTJS_ASSERT(platform_data != NULL); + + if (!platform_data->is_open) { + return false; // pin is not open + } + + platform_data->is_open = false; + return true; +} diff --git a/src/platform/nuttx/iotjs_module_adc-nuttx.c b/src/modules/nuttx/iotjs_module_adc-nuttx.c similarity index 59% rename from src/platform/nuttx/iotjs_module_adc-nuttx.c rename to src/modules/nuttx/iotjs_module_adc-nuttx.c index a2f9eb09fc..2a6561e4b6 100644 --- a/src/platform/nuttx/iotjs_module_adc-nuttx.c +++ b/src/modules/nuttx/iotjs_module_adc-nuttx.c @@ -13,8 +13,9 @@ * limitations under the License. */ -#if defined(__NUTTX__) - +#if !defined(__NUTTX__) +#error "Module __FILE__ is for NuttX only" +#endif #include #include @@ -23,24 +24,47 @@ #include "iotjs_def.h" #include "iotjs_systemio-nuttx.h" #include "modules/iotjs_module_adc.h" -#include "modules/iotjs_module_stm32f4dis.h" - #define ADC_DEVICE_PATH_FORMAT "/dev/adc%d" #define ADC_DEVICE_PATH_BUFFER_SIZE 12 +struct iotjs_adc_platform_data_s { + uint32_t pin; +}; + +void iotjs_adc_create_platform_data(iotjs_adc_t* adc) { + adc->platform_data = IOTJS_ALLOC(iotjs_adc_platform_data_t); + adc->platform_data->pin = 0; +} + + +void iotjs_adc_destroy_platform_data(iotjs_adc_platform_data_t* platform_data) { + IOTJS_RELEASE(platform_data); +} + + +jerry_value_t iotjs_adc_set_platform_config(iotjs_adc_t* adc, + const jerry_value_t jconfig) { + iotjs_adc_platform_data_t* platform_data = adc->platform_data; + + JS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->pin, + IOTJS_MAGIC_STRING_PIN, number); -static void iotjs_adc_get_path(char* buffer, int32_t number) { + return jerry_create_undefined(); +} + + +static void adc_get_path(char* buffer, int32_t number) { // Create ADC device path snprintf(buffer, ADC_DEVICE_PATH_BUFFER_SIZE - 1, ADC_DEVICE_PATH_FORMAT, number); } -static bool iotjs_adc_read_data(uint32_t pin, struct adc_msg_s* msg) { +static bool adc_read_data(uint32_t pin, struct adc_msg_s* msg) { int32_t adc_number = ADC_GET_NUMBER(pin); char path[ADC_DEVICE_PATH_BUFFER_SIZE] = { 0 }; - iotjs_adc_get_path(path, adc_number); + adc_get_path(path, adc_number); const iotjs_environment_t* env = iotjs_environment_get(); uv_loop_t* loop = iotjs_environment_loop(env); @@ -68,33 +92,35 @@ static bool iotjs_adc_read_data(uint32_t pin, struct adc_msg_s* msg) { return false; } - DDLOG("ADC Read - path: %s, value: %d", path, msg->am_data); + DDDLOG("ADC Read - path: %s, value: %d", path, msg->am_data); return true; } -int32_t iotjs_adc_read(iotjs_adc_t* adc) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_adc_t, adc); +bool iotjs_adc_read(iotjs_adc_t* adc) { + iotjs_adc_platform_data_t* platform_data = adc->platform_data; struct adc_msg_s msg; - if (!iotjs_adc_read_data(_this->pin, &msg)) { - return -1; + if (!adc_read_data(platform_data->pin, &msg)) { + return false; } - return msg.am_data; + adc->value = msg.am_data; + + return true; } bool iotjs_adc_close(iotjs_adc_t* adc) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_adc_t, adc); + iotjs_adc_platform_data_t* platform_data = adc->platform_data; - uint32_t pin = _this->pin; + uint32_t pin = platform_data->pin; int32_t adc_number = ADC_GET_NUMBER(pin); char path[ADC_DEVICE_PATH_BUFFER_SIZE] = { 0 }; - iotjs_adc_get_path(path, adc_number); + adc_get_path(path, adc_number); // Release driver if (unregister_driver(path) < 0) { @@ -107,28 +133,23 @@ bool iotjs_adc_close(iotjs_adc_t* adc) { } -void iotjs_adc_open_worker(uv_work_t* work_req) { - ADC_WORKER_INIT; - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_adc_t, adc); +bool iotjs_adc_open(iotjs_adc_t* adc) { + iotjs_adc_platform_data_t* platform_data = adc->platform_data; - uint32_t pin = _this->pin; + uint32_t pin = platform_data->pin; int32_t adc_number = ADC_GET_NUMBER(pin); int32_t timer = SYSIO_GET_TIMER(pin); struct adc_dev_s* adc_dev = iotjs_adc_config_nuttx(adc_number, timer, pin); char path[ADC_DEVICE_PATH_BUFFER_SIZE] = { 0 }; - iotjs_adc_get_path(path, adc_number); + adc_get_path(path, adc_number); if (adc_register(path, adc_dev) != 0) { - req_data->result = false; - return; + return false; } - DDLOG("%s - path: %s, number: %d, timer: %d", __func__, path, adc_number, - timer); + DDDLOG("%s - path: %s, number: %d, timer: %d", __func__, path, adc_number, + timer); - req_data->result = true; + return true; } - - -#endif // __NUTTX__ diff --git a/src/platform/nuttx/iotjs_module_blehcisocket-nuttx.c b/src/modules/nuttx/iotjs_module_blehcisocket-nuttx.c similarity index 51% rename from src/platform/nuttx/iotjs_module_blehcisocket-nuttx.c rename to src/modules/nuttx/iotjs_module_blehcisocket-nuttx.c index 45e76c14b1..d838d17585 100644 --- a/src/platform/nuttx/iotjs_module_blehcisocket-nuttx.c +++ b/src/modules/nuttx/iotjs_module_blehcisocket-nuttx.c @@ -13,92 +13,85 @@ * limitations under the License. */ -#ifndef IOTJS_MODULE_BLE_HCI_SOCKET_LINUX_GENERAL_INL_H -#define IOTJS_MODULE_BLE_HCI_SOCKET_LINUX_GENERAL_INL_H - - #include "iotjs_def.h" #include "modules/iotjs_module_blehcisocket.h" -#define THIS iotjs_blehcisocket_t* blehcisocket - -void iotjs_blehcisocket_initialize(THIS) { +void iotjs_blehcisocket_initialize(iotjs_blehcisocket_t* blehcisocket) { IOTJS_ASSERT(!"Not implemented"); } -void iotjs_blehcisocket_close(THIS) { +void iotjs_blehcisocket_close(iotjs_blehcisocket_t* blehcisocket) { IOTJS_ASSERT(!"Not implemented"); } -void iotjs_blehcisocket_start(THIS) { +void iotjs_blehcisocket_start(iotjs_blehcisocket_t* blehcisocket) { IOTJS_ASSERT(!"Not implemented"); } -int iotjs_blehcisocket_bindRaw(THIS, int* devId) { +int iotjs_blehcisocket_bindRaw(iotjs_blehcisocket_t* blehcisocket, int* devId) { IOTJS_ASSERT(!"Not implemented"); return 0; } -int iotjs_blehcisocket_bindUser(THIS, int* devId) { +int iotjs_blehcisocket_bindUser(iotjs_blehcisocket_t* blehcisocket, + int* devId) { IOTJS_ASSERT(!"Not implemented"); return 0; } -void iotjs_blehcisocket_bindControl(THIS) { +void iotjs_blehcisocket_bindControl(iotjs_blehcisocket_t* blehcisocket) { IOTJS_ASSERT(!"Not implemented"); } -bool iotjs_blehcisocket_isDevUp(THIS) { +bool iotjs_blehcisocket_isDevUp(iotjs_blehcisocket_t* blehcisocket) { IOTJS_ASSERT(!"Not implemented"); return false; } -void iotjs_blehcisocket_setFilter(THIS, char* data, size_t length) { +void iotjs_blehcisocket_setFilter(iotjs_blehcisocket_t* blehcisocket, + char* data, size_t length) { IOTJS_ASSERT(!"Not implemented"); } -void iotjs_blehcisocket_poll(THIS) { +void iotjs_blehcisocket_poll(iotjs_blehcisocket_t* blehcisocket) { IOTJS_ASSERT(!"Not implemented"); } -void iotjs_blehcisocket_stop(THIS) { +void iotjs_blehcisocket_stop(iotjs_blehcisocket_t* blehcisocket) { IOTJS_ASSERT(!"Not implemented"); } -void iotjs_blehcisocket_write(THIS, char* data, size_t length) { +void iotjs_blehcisocket_write(iotjs_blehcisocket_t* blehcisocket, char* data, + size_t length) { IOTJS_ASSERT(!"Not implemented"); } -void iotjs_blehcisocket_emitErrnoError(THIS) { +void iotjs_blehcisocket_emitErrnoError(iotjs_blehcisocket_t* blehcisocket) { IOTJS_ASSERT(!"Not implemented"); } -int iotjs_blehcisocket_devIdFor(THIS, int* pDevId, bool isUp) { +int iotjs_blehcisocket_devIdFor(iotjs_blehcisocket_t* blehcisocket, int* pDevId, + bool isUp) { IOTJS_ASSERT(!"Not implemented"); return 0; } -int iotjs_blehcisocket_kernelDisconnectWorkArounds(THIS, int length, - char* data) { +int iotjs_blehcisocket_kernelDisconnectWorkArounds( + iotjs_blehcisocket_t* blehcisocket, int length, char* data) { IOTJS_ASSERT(!"Not implemented"); return 0; } - - -#undef THIS - -#endif /* IOTJS_MODULE_BLE_HCI_SOCKET_LINUX_GENERAL_INL_H */ diff --git a/src/platform/nuttx/stm32f4dis/iotjs_module_gpio-nuttx-stm32f4dis.c b/src/modules/nuttx/iotjs_module_gpio-nuttx.c similarity index 57% rename from src/platform/nuttx/stm32f4dis/iotjs_module_gpio-nuttx-stm32f4dis.c rename to src/modules/nuttx/iotjs_module_gpio-nuttx.c index 832b3c4eaa..974083d8c2 100644 --- a/src/platform/nuttx/stm32f4dis/iotjs_module_gpio-nuttx-stm32f4dis.c +++ b/src/modules/nuttx/iotjs_module_gpio-nuttx.c @@ -34,47 +34,59 @@ uint32_t gpioMode[] = { }; -bool iotjs_gpio_write(iotjs_gpio_t* gpio, bool value) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_gpio_t, gpio); +void iotjs_gpio_create_platform_data(iotjs_gpio_t* gpio) { +} - DDDLOG("%s - pin: %d, value: %d", __func__, _this->pin, value); - stm32_gpiowrite(_this->pin, value); - return true; +void iotjs_gpio_destroy_platform_data( + iotjs_gpio_platform_data_t* platform_data) { } -int iotjs_gpio_read(iotjs_gpio_t* gpio) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_gpio_t, gpio); +bool iotjs_gpio_write(iotjs_gpio_t* gpio) { + DDDLOG("%s - pin: %d, value: %d", __func__, gpio->pin, gpio->value); + stm32_gpiowrite(gpio->pin, gpio->value); - DDDLOG("%s - pin: %d", __func__, _this->pin); - return stm32_gpioread(_this->pin); + return true; } -bool iotjs_gpio_close(iotjs_gpio_t* gpio) { - iotjs_gpio_write(gpio, 0); +bool iotjs_gpio_read(iotjs_gpio_t* gpio) { + DDDLOG("%s - pin: %d", __func__, gpio->pin); + gpio->value = stm32_gpioread(gpio->pin); return true; } -void iotjs_gpio_open_worker(uv_work_t* work_req) { - GPIO_WORKER_INIT; - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_gpio_t, gpio); +bool iotjs_gpio_close(iotjs_gpio_t* gpio) { + iotjs_gpio_write(gpio); + + return true; +} - DDDLOG("%s - pin: %d, dir: %d, mode: %d", __func__, _this->pin, - _this->direction, _this->mode); +static bool gpio_set_config(iotjs_gpio_t* gpio) { uint32_t cfgset = 0; // Set pin direction and mode - cfgset = gpioDirection[_this->direction] | gpioMode[_this->mode] | _this->pin; + cfgset = gpioDirection[gpio->direction] | gpioMode[gpio->mode] | gpio->pin; if (stm32_configgpio(cfgset) != GPIO_CONFIG_OK) { - req_data->result = false; - return; + return false; } - req_data->result = true; + return true; +} + + +bool iotjs_gpio_open(iotjs_gpio_t* gpio) { + DDDLOG("%s - pin: %d, dir: %d, mode: %d", __func__, gpio->pin, + gpio->direction, gpio->mode); + return gpio_set_config(gpio); +} + + +bool iotjs_gpio_set_direction(iotjs_gpio_t* gpio) { + return gpio_set_config(gpio); } diff --git a/src/modules/nuttx/iotjs_module_i2c-nuttx.c b/src/modules/nuttx/iotjs_module_i2c-nuttx.c new file mode 100644 index 0000000000..6ce25f8958 --- /dev/null +++ b/src/modules/nuttx/iotjs_module_i2c-nuttx.c @@ -0,0 +1,127 @@ +/* Copyright 2016-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 !defined(__NUTTX__) +#error "Module __FILE__ is for nuttx only" +#endif + +#include + +#include "iotjs_systemio-nuttx.h" + +#include "modules/iotjs_module_i2c.h" + + +#define I2C_DEFAULT_FREQUENCY 400000 +#define I2C_DEFAULT_ADDRESS_LENGTH 7 + +struct iotjs_i2c_platform_data_s { + int bus; + struct i2c_master_s* i2c_master; + struct i2c_config_s config; +}; + +void iotjs_i2c_create_platform_data(iotjs_i2c_t* i2c) { + i2c->platform_data = IOTJS_ALLOC(iotjs_i2c_platform_data_t); + + i2c->platform_data->i2c_master = NULL; +} + +void iotjs_i2c_destroy_platform_data(iotjs_i2c_platform_data_t* pdata) { + IOTJS_RELEASE(pdata); +} + +jerry_value_t iotjs_i2c_set_platform_config(iotjs_i2c_t* i2c, + const jerry_value_t jconfig) { + iotjs_i2c_platform_data_t* platform_data = i2c->platform_data; + + JS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->bus, + IOTJS_MAGIC_STRING_BUS, number); + + return jerry_create_undefined(); +} + +#define I2C_METHOD_HEADER(arg) \ + iotjs_i2c_platform_data_t* platform_data = arg->platform_data; \ + IOTJS_ASSERT(platform_data); \ + if (!platform_data->i2c_master) { \ + DLOG("%s: I2C is not opened", __func__); \ + return false; \ + } + +bool iotjs_i2c_open(iotjs_i2c_t* i2c) { + iotjs_i2c_platform_data_t* platform_data = i2c->platform_data; + IOTJS_ASSERT(platform_data); + + platform_data->config.address = i2c->address; + platform_data->config.addrlen = I2C_DEFAULT_ADDRESS_LENGTH; + + platform_data->i2c_master = iotjs_i2c_config_nuttx(platform_data->bus); + if (!platform_data->i2c_master) { + DLOG("%s : cannot open", __func__); + return false; + } + + platform_data->config.frequency = I2C_DEFAULT_FREQUENCY; + + return true; +} + +bool iotjs_i2c_close(iotjs_i2c_t* i2c) { + I2C_METHOD_HEADER(i2c); + + if (iotjs_i2c_unconfig_nuttx(platform_data->i2c_master) < 0) { + DLOG("%s : cannot close", __func__); + return false; + } + + return true; +} + +bool iotjs_i2c_write(iotjs_i2c_t* i2c) { + I2C_METHOD_HEADER(i2c); + + uint8_t len = i2c->buf_len; + uint8_t* data = (uint8_t*)i2c->buf_data; + IOTJS_ASSERT(len > 0); + + int ret = + i2c_write(platform_data->i2c_master, &platform_data->config, data, len); + + IOTJS_RELEASE(i2c->buf_data); + + if (ret < 0) { + DLOG("%s : cannot write - %d", __func__, ret); + return false; + } + return true; +} + +bool iotjs_i2c_read(iotjs_i2c_t* i2c) { + I2C_METHOD_HEADER(i2c); + + uint8_t len = i2c->buf_len; + i2c->buf_data = iotjs_buffer_allocate(len); + IOTJS_ASSERT(len > 0); + + int ret = i2c_read(platform_data->i2c_master, &platform_data->config, + (uint8_t*)i2c->buf_data, len); + if (ret != 0) { + DLOG("%s : cannot read - %d", __func__, ret); + return false; + } + + return true; +} diff --git a/src/platform/nuttx/iotjs_module_pwm-nuttx.c b/src/modules/nuttx/iotjs_module_pwm-nuttx.c similarity index 52% rename from src/platform/nuttx/iotjs_module_pwm-nuttx.c rename to src/modules/nuttx/iotjs_module_pwm-nuttx.c index 39343eebd3..3c833951f5 100644 --- a/src/platform/nuttx/iotjs_module_pwm-nuttx.c +++ b/src/modules/nuttx/iotjs_module_pwm-nuttx.c @@ -28,24 +28,41 @@ #define PWM_DEVICE_PATH_FORMAT "/dev/pwm%d" #define PWM_DEVICE_PATH_BUFFER_SIZE 12 +struct iotjs_pwm_platform_data_s { + int device_fd; +}; -static bool iotjs_pwm_set_options(iotjs_pwm_t* pwm) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_t, pwm); +void iotjs_pwm_create_platform_data(iotjs_pwm_t* pwm) { + pwm->platform_data = IOTJS_ALLOC(iotjs_pwm_platform_data_t); + pwm->platform_data->device_fd = -1; +} + +void iotjs_pwm_destroy_platform_data(iotjs_pwm_platform_data_t* pdata) { + IOTJS_RELEASE(pdata); +} + +jerry_value_t iotjs_pwm_set_platform_config(iotjs_pwm_t* pwm, + const jerry_value_t jconfig) { + return jerry_create_undefined(); +} - int fd = _this->device_fd; +static bool pwm_set_options(iotjs_pwm_t* pwm) { + iotjs_pwm_platform_data_t* platform_data = pwm->platform_data; + + int fd = platform_data->device_fd; if (fd < 0) { - DDLOG("%s - file open failed", __func__); + DLOG("%s - file open failed", __func__); return false; } struct pwm_info_s info; // Clamp so that the value inverted fits into uint32 - if (_this->period < 2.33E-10) - _this->period = 2.33E-10; - info.frequency = (uint32_t)(1.0 / _this->period); + if (pwm->period < 2.33E-10) + pwm->period = 2.33E-10; + info.frequency = (uint32_t)(1.0 / pwm->period); - double duty_value = _this->duty_cycle * (1 << 16); // 16 bit timer + double duty_value = pwm->duty_cycle * (1 << 16); // 16 bit timer if (duty_value > 0xffff) duty_value = 0xffff; else if (duty_value < 1) @@ -63,89 +80,81 @@ static bool iotjs_pwm_set_options(iotjs_pwm_t* pwm) { return true; } - -void iotjs_pwm_open_worker(uv_work_t* work_req) { - PWM_WORKER_INIT; - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_t, pwm); - - int timer = SYSIO_GET_TIMER(_this->pin); +bool iotjs_pwm_open(iotjs_pwm_t* pwm) { + int timer = SYSIO_GET_TIMER(pwm->pin); char path[PWM_DEVICE_PATH_BUFFER_SIZE] = { 0 }; if (snprintf(path, PWM_DEVICE_PATH_BUFFER_SIZE, PWM_DEVICE_PATH_FORMAT, - timer) < 0) { - req_data->result = false; - return; + (timer - 1)) < 0) { + return false; } - struct pwm_lowerhalf_s* pwm_lowerhalf = - iotjs_pwm_config_nuttx(timer, _this->pin); + if (access(path, F_OK) != 0) { + struct pwm_lowerhalf_s* pwm_lowerhalf = + iotjs_pwm_config_nuttx(timer, pwm->pin); - DDDLOG("%s - path: %s, timer: %d\n", __func__, path, timer); + DDDLOG("%s - path: %s, timer: %d\n", __func__, path, timer); - if (pwm_register(path, pwm_lowerhalf) != 0) { - req_data->result = false; - return; + if (pwm_register(path, pwm_lowerhalf) != 0) { + return false; + } } // File open - _this->device_fd = open(path, O_RDONLY); - if (_this->device_fd < 0) { - DDLOG("%s - file open failed", __func__); - req_data->result = false; - return; + iotjs_pwm_platform_data_t* platform_data = pwm->platform_data; + platform_data->device_fd = open(path, O_RDONLY); + if (platform_data->device_fd < 0) { + DLOG("%s - file open failed", __func__); + return false; } - if (!iotjs_pwm_set_options(pwm)) { - req_data->result = false; + if (!pwm_set_options(pwm)) { + return false; } - req_data->result = true; + return true; } - bool iotjs_pwm_set_period(iotjs_pwm_t* pwm) { - return iotjs_pwm_set_options(pwm); + return pwm_set_options(pwm); } - bool iotjs_pwm_set_dutycycle(iotjs_pwm_t* pwm) { - return iotjs_pwm_set_options(pwm); + return pwm_set_options(pwm); } - bool iotjs_pwm_set_enable(iotjs_pwm_t* pwm) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_t, pwm); + iotjs_pwm_platform_data_t* platform_data = pwm->platform_data; - int fd = _this->device_fd; + int fd = platform_data->device_fd; if (fd < 0) { - DDLOG("%s - file open failed", __func__); + DLOG("%s - file open failed", __func__); return false; } - DDDLOG("%s - enable: %d", __func__, _this->enable); + DDDLOG("%s - enable: %d", __func__, pwm->enable); int ret; - if (_this->enable) { + if (pwm->enable) { ret = ioctl(fd, PWMIOC_START, 0); } else { ret = ioctl(fd, PWMIOC_STOP, 0); } if (ret < 0) { - DDLOG("%s - setEnable failed", __func__); + DLOG("%s - setEnable failed", __func__); return false; } return true; } - bool iotjs_pwm_close(iotjs_pwm_t* pwm) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_t, pwm); + iotjs_pwm_platform_data_t* platform_data = pwm->platform_data; - int fd = _this->device_fd; + int fd = platform_data->device_fd; if (fd < 0) { - DDLOG("%s - file not opened", __func__); + DLOG("%s - file not opened", __func__); return false; } @@ -153,9 +162,9 @@ bool iotjs_pwm_close(iotjs_pwm_t* pwm) { // Close file close(fd); - _this->device_fd = -1; + platform_data->device_fd = -1; - uint32_t timer = SYSIO_GET_TIMER(_this->pin); + uint32_t timer = SYSIO_GET_TIMER(pwm->pin); char path[PWM_DEVICE_PATH_BUFFER_SIZE] = { 0 }; if (snprintf(path, PWM_DEVICE_PATH_BUFFER_SIZE - 1, PWM_DEVICE_PATH_FORMAT, timer) < 0) { @@ -165,7 +174,7 @@ bool iotjs_pwm_close(iotjs_pwm_t* pwm) { // Release driver unregister_driver(path); - iotjs_gpio_unconfig_nuttx(_this->pin); + iotjs_gpio_unconfig_nuttx(pwm->pin); return true; } diff --git a/src/modules/nuttx/iotjs_module_spi-nuttx.c b/src/modules/nuttx/iotjs_module_spi-nuttx.c new file mode 100644 index 0000000000..72cfa0b8a1 --- /dev/null +++ b/src/modules/nuttx/iotjs_module_spi-nuttx.c @@ -0,0 +1,109 @@ +/* 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. + */ + +#if !defined(__NUTTX__) +#error "Module __FILE__ is for nuttx only" +#endif + +#include + +#include "iotjs_systemio-nuttx.h" +#include "chip.h" +#include "modules/iotjs_module_spi.h" + + +struct iotjs_spi_platform_data_s { + int bus; + uint32_t cs_chip; + struct spi_dev_s* spi_dev; +}; + +void iotjs_spi_create_platform_data(iotjs_spi_t* spi) { + spi->platform_data = IOTJS_ALLOC(iotjs_spi_platform_data_t); + spi->platform_data->bus = -1; + spi->platform_data->cs_chip = 0; + spi->platform_data->spi_dev = NULL; +} + +void iotjs_spi_destroy_platform_data(iotjs_spi_platform_data_t* pdata) { + IOTJS_RELEASE(pdata); +} + +jerry_value_t iotjs_spi_set_platform_config(iotjs_spi_t* spi, + const jerry_value_t jconfig) { + iotjs_spi_platform_data_t* platform_data = spi->platform_data; + + JS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->bus, + IOTJS_MAGIC_STRING_BUS, number); + + return jerry_create_undefined(); +} + +bool iotjs_spi_transfer(iotjs_spi_t* spi) { + iotjs_spi_platform_data_t* platform_data = spi->platform_data; + + struct spi_dev_s* spi_dev = platform_data->spi_dev; + + SPI_LOCK(spi_dev, true); + + SPI_SETFREQUENCY(spi_dev, spi->max_speed); + + SPI_SETMODE(spi_dev, spi->mode); + SPI_SETBITS(spi_dev, spi->bits_per_word); + + // Select the SPI + iotjs_gpio_write_nuttx(platform_data->cs_chip, false); + + SPI_EXCHANGE(spi_dev, spi->tx_buf_data, spi->rx_buf_data, spi->buf_len); + + // Unselect the SPI device + iotjs_gpio_write_nuttx(platform_data->cs_chip, true); + + SPI_LOCK(spi_dev, false); + + return true; +} + +bool iotjs_spi_close(iotjs_spi_t* spi) { + iotjs_spi_platform_data_t* platform_data = spi->platform_data; + + iotjs_gpio_unconfig_nuttx(platform_data->cs_chip); + + return true; +} + +bool iotjs_spi_open(iotjs_spi_t* spi) { + iotjs_spi_platform_data_t* platform_data = spi->platform_data; + + switch (platform_data->bus) { + case 1: + platform_data->cs_chip = (GPIO_OUTPUT | GPIO_PUSHPULL | GPIO_SPEED_50MHz | + GPIO_PORTA | GPIO_PIN15 | GPIO_OUTPUT_SET); + break; + default: + return false; + } + + iotjs_gpio_config_nuttx(platform_data->cs_chip); + + if (!(platform_data->spi_dev = + iotjs_spi_config_nuttx(platform_data->bus, + platform_data->cs_chip))) { + DLOG("%s - SPI open failed %d", __func__, platform_data->bus); + return false; + } + + return true; +} diff --git a/src/platform/nuttx/iotjs_module_stm32f4dis-nuttx.c b/src/modules/nuttx/iotjs_module_stm32f4dis-nuttx.c similarity index 79% rename from src/platform/nuttx/iotjs_module_stm32f4dis-nuttx.c rename to src/modules/nuttx/iotjs_module_stm32f4dis-nuttx.c index 8815b501e3..c1d35cfb4c 100644 --- a/src/platform/nuttx/iotjs_module_stm32f4dis-nuttx.c +++ b/src/modules/nuttx/iotjs_module_stm32f4dis-nuttx.c @@ -13,7 +13,7 @@ * limitations under the License. */ -#if defined(__NUTTX__) && TARGET_BOARD == STM32F4DIS +#if defined(__NUTTX__) && TARGET_BOARD == stm32f4dis #include "iotjs_def.h" @@ -24,7 +24,7 @@ #if ENABLE_MODULE_ADC -static void iotjs_pin_initialize_adc(const iotjs_jval_t* jobj) { +static void iotjs_pin_initialize_adc(jerry_value_t jobj) { unsigned int number_bit; // ADC pin name is "ADC.(number)_(timer)". @@ -64,7 +64,7 @@ static void iotjs_pin_initialize_adc(const iotjs_jval_t* jobj) { #if ENABLE_MODULE_GPIO -static void iotjs_pin_initialize_gpio(const iotjs_jval_t* jobj) { +static void iotjs_pin_initialize_gpio(jerry_value_t jobj) { // Set GPIO pin from configuration bits of nuttx. // GPIO pin name is "P(port)(pin)". #define SET_GPIO_CONSTANT(port, pin) \ @@ -107,24 +107,24 @@ static void iotjs_pin_initialize_gpio(const iotjs_jval_t* jobj) { #if ENABLE_MODULE_PWM -static void iotjs_pin_initialize_pwm(const iotjs_jval_t* jobj) { +static void iotjs_pin_initialize_pwm(jerry_value_t jobj) { unsigned int timer_bit; // Set PWM pin from configuration bits of nuttx. // PWM pin name is "PWM(timer).CH(channel)_(n)". -#define SET_GPIO_CONSTANT(timer, channel, order) \ - timer_bit = (GPIO_TIM##timer##_CH##channel##OUT_##order); \ - timer_bit |= (SYSIO_TIMER_NUMBER(timer)); \ - iotjs_jval_set_property_number(&jtim##timer, "CH" #channel "_" #order, \ +#define SET_GPIO_CONSTANT(timer, channel, order) \ + timer_bit = (GPIO_TIM##timer##_CH##channel##OUT_##order); \ + timer_bit |= (SYSIO_TIMER_NUMBER(timer)); \ + iotjs_jval_set_property_number(jtim##timer, "CH" #channel "_" #order, \ timer_bit); #define SET_GPIO_CONSTANT_CHANNEL(timer, channel) \ SET_GPIO_CONSTANT(timer, channel, 1); \ SET_GPIO_CONSTANT(timer, channel, 2); -#define SET_GPIO_CONSTANT_TIM(timer) \ - iotjs_jval_t jtim##timer = iotjs_jval_create_object(); \ - iotjs_jval_set_property_jval(jobj, "PWM" #timer, &jtim##timer); +#define SET_GPIO_CONSTANT_TIM(timer) \ + jerry_value_t jtim##timer = jerry_create_object(); \ + iotjs_jval_set_property_jval(jobj, "PWM" #timer, jtim##timer); #define SET_GPIO_CONSTANT_TIM_1(timer) \ SET_GPIO_CONSTANT_TIM(timer); \ @@ -143,32 +143,32 @@ static void iotjs_pin_initialize_pwm(const iotjs_jval_t* jobj) { SET_GPIO_CONSTANT_CHANNEL(timer, 4); SET_GPIO_CONSTANT_TIM_4(1); // PA8, PE9, PA9, PE11, PA10, PE13, PA11, PE14 - iotjs_jval_destroy(&jtim1); + jerry_release_value(jtim1); SET_GPIO_CONSTANT_TIM_4(2); // PA0, PA15, PA1, PB3, PA2, PB10, PA3, PB11 - iotjs_jval_set_property_number(&jtim2, "CH1_3", GPIO_TIM2_CH1OUT_3); // PA5 - iotjs_jval_destroy(&jtim2); + iotjs_jval_set_property_number(jtim2, "CH1_3", GPIO_TIM2_CH1OUT_3); // PA5 + jerry_release_value(jtim2); SET_GPIO_CONSTANT_TIM_4(3); // PA6, PB4, PA7, PB5, PB0, PC8, PB1, PC9 - iotjs_jval_set_property_number(&jtim3, "CH1_3", GPIO_TIM3_CH1OUT_3); // PC6 - iotjs_jval_set_property_number(&jtim3, "CH2_3", GPIO_TIM3_CH2OUT_3); // PC7 - iotjs_jval_destroy(&jtim3); + iotjs_jval_set_property_number(jtim3, "CH1_3", GPIO_TIM3_CH1OUT_3); // PC6 + iotjs_jval_set_property_number(jtim3, "CH2_3", GPIO_TIM3_CH2OUT_3); // PC7 + jerry_release_value(jtim3); SET_GPIO_CONSTANT_TIM_4(4); // PB6, PD12, PB7, PD13, PB8, PD14, PB9, PD15 - iotjs_jval_destroy(&jtim4); + jerry_release_value(jtim4); SET_GPIO_CONSTANT_TIM_4(5); // PA0, PH10, PA1, PH11, PA2, PH12, PA3, PI0 - iotjs_jval_destroy(&jtim5); + jerry_release_value(jtim5); SET_GPIO_CONSTANT_TIM_4(8); // PC6, PI5, PC7, PI6, PC8, PI7, PC9, PI2 - iotjs_jval_destroy(&jtim8); + jerry_release_value(jtim8); SET_GPIO_CONSTANT_TIM_2(9); // PA2, PE5, PA3, PE6 - iotjs_jval_destroy(&jtim9); + jerry_release_value(jtim9); SET_GPIO_CONSTANT_TIM_1(10); // PB8, PF6 - iotjs_jval_destroy(&jtim10); + jerry_release_value(jtim10); SET_GPIO_CONSTANT_TIM_1(11); // PB9, PF7 - iotjs_jval_destroy(&jtim11); + jerry_release_value(jtim11); SET_GPIO_CONSTANT_TIM_2(12); // PH6, PB14, PB15, PH9 - iotjs_jval_destroy(&jtim12); + jerry_release_value(jtim12); SET_GPIO_CONSTANT_TIM_1(13); // PA6, PF8 - iotjs_jval_destroy(&jtim13); + jerry_release_value(jtim13); SET_GPIO_CONSTANT_TIM_1(14); // PA7, PF9 - iotjs_jval_destroy(&jtim14); + jerry_release_value(jtim14); #undef SET_GPIO_CONSTANT_TIM_4 #undef SET_GPIO_CONSTANT_TIM_2 @@ -181,23 +181,23 @@ static void iotjs_pin_initialize_pwm(const iotjs_jval_t* jobj) { #endif /* ENABLE_MODULE_PWM */ -void iotjs_stm32f4dis_pin_initialize(const iotjs_jval_t* jobj) { - iotjs_jval_t jpin = iotjs_jval_create_object(); - iotjs_jval_set_property_jval(jobj, "pin", &jpin); +void iotjs_stm32f4dis_pin_initialize(jerry_value_t jobj) { + jerry_value_t jpin = jerry_create_object(); + iotjs_jval_set_property_jval(jobj, "pin", jpin); #if ENABLE_MODULE_ADC - iotjs_pin_initialize_adc(&jpin); + iotjs_pin_initialize_adc(jpin); #endif /* ENABLE_MODULE_ADC */ #if ENABLE_MODULE_GPIO - iotjs_pin_initialize_gpio(&jpin); + iotjs_pin_initialize_gpio(jpin); #endif /* ENABLE_MODULE_GPIO */ #if ENABLE_MODULE_PWM - iotjs_pin_initialize_pwm(&jpin); + iotjs_pin_initialize_pwm(jpin); #endif /* ENABLE_MODULE_PWM */ - iotjs_jval_destroy(&jpin); + jerry_release_value(jpin); } diff --git a/src/modules/nuttx/iotjs_module_stm32f7nucleo-nuttx.c b/src/modules/nuttx/iotjs_module_stm32f7nucleo-nuttx.c new file mode 100644 index 0000000000..5bb0e2fb68 --- /dev/null +++ b/src/modules/nuttx/iotjs_module_stm32f7nucleo-nuttx.c @@ -0,0 +1,154 @@ +/* Copyright 2019-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 defined(__NUTTX__) && defined(TARGET_BOARD_STM32F7NUCLEO) + +#include "iotjs_systemio-nuttx.h" +#include "stm32_gpio.h" + +#include "iotjs_def.h" +#include "modules/iotjs_module_stm32f7nucleo.h" + +#if ENABLE_MODULE_ADC +static void iotjs_pin_initialize_adc(jerry_value_t jobj) { + unsigned int number_bit; + +// ADC pin name is "ADC(number)_(timer)". +#define SET_ADC_CONSTANT(number, timer) \ + number_bit = (GPIO_ADC##number##_IN##timer); \ + number_bit |= (ADC_NUMBER(number)); \ + number_bit |= (SYSIO_TIMER_NUMBER(timer)); \ + iotjs_jval_set_property_number(jobj, "ADC" #number "_" #timer, number_bit); + +#define SET_ADC_CONSTANT_NUMBER(number) SET_ADC_CONSTANT(number, 3); + + SET_ADC_CONSTANT_NUMBER(1); + +#undef SET_ADC_CONSTANT_NUMBER +#undef SET_ADC_CONSTANT +} +#endif /* ENABLE_MODULE_ADC */ + +#if ENABLE_MODULE_GPIO + +static void iotjs_pin_initialize_gpio(jerry_value_t jobj) { +// Set GPIO pin from configuration bits of nuttx. +// GPIO pin name is "P(port)(pin)". +#define SET_GPIO_CONSTANT(port, pin) \ + iotjs_jval_set_property_number(jobj, "P" #port #pin, \ + (GPIO_PORT##port | GPIO_PIN##pin)); + +#define SET_GPIO_CONSTANT_PORT(port) \ + SET_GPIO_CONSTANT(port, 0); \ + SET_GPIO_CONSTANT(port, 1); \ + SET_GPIO_CONSTANT(port, 2); \ + SET_GPIO_CONSTANT(port, 3); \ + SET_GPIO_CONSTANT(port, 4); \ + SET_GPIO_CONSTANT(port, 5); \ + SET_GPIO_CONSTANT(port, 6); \ + SET_GPIO_CONSTANT(port, 7); \ + SET_GPIO_CONSTANT(port, 8); \ + SET_GPIO_CONSTANT(port, 9); \ + SET_GPIO_CONSTANT(port, 10); \ + SET_GPIO_CONSTANT(port, 11); \ + SET_GPIO_CONSTANT(port, 12); \ + SET_GPIO_CONSTANT(port, 13); \ + SET_GPIO_CONSTANT(port, 14); \ + SET_GPIO_CONSTANT(port, 15); + + SET_GPIO_CONSTANT_PORT(A); + SET_GPIO_CONSTANT_PORT(B); + SET_GPIO_CONSTANT_PORT(C); + SET_GPIO_CONSTANT_PORT(D); + SET_GPIO_CONSTANT_PORT(E); + + SET_GPIO_CONSTANT(H, 0); + SET_GPIO_CONSTANT(H, 1); + +#undef SET_GPIO_CONSTANT_PORT +#undef SET_GPIO_CONSTANT +} + +#endif /* ENABLE_MODULE_GPIO */ + + +#if ENABLE_MODULE_PWM + +static void iotjs_pin_initialize_pwm(jerry_value_t jobj) { + unsigned int timer_bit; + +// Set PWM pin from configuration bits of nuttx. +// PWM pin name is "PWM(timer).CH(channel)_(n)". +#define SET_GPIO_CONSTANT(timer, channel, order) \ + timer_bit = (GPIO_TIM##timer##_CH##channel##OUT_##order); \ + timer_bit |= (SYSIO_TIMER_NUMBER(timer)); \ + iotjs_jval_set_property_number(jtim##timer, "CH" #channel "_" #order, \ + timer_bit); + +#define SET_GPIO_CONSTANT_CHANNEL(timer, channel) \ + SET_GPIO_CONSTANT(timer, channel, 1); + +#define SET_GPIO_CONSTANT_TIM(timer) \ + jerry_value_t jtim##timer = jerry_create_object(); \ + iotjs_jval_set_property_jval(jobj, "PWM" #timer, jtim##timer); + + +#define SET_GPIO_CONSTANT_TIM_1(timer) \ + SET_GPIO_CONSTANT_TIM(timer); \ + SET_GPIO_CONSTANT_CHANNEL(timer, 1); + + SET_GPIO_CONSTANT_TIM_1(1); + jerry_release_value(jtim1); + + SET_GPIO_CONSTANT_TIM_1(2); + jerry_release_value(jtim2); + + SET_GPIO_CONSTANT_TIM_1(3); + jerry_release_value(jtim3); + + SET_GPIO_CONSTANT_TIM_1(4); + jerry_release_value(jtim4); + +#undef SET_GPIO_CONSTANT_TIM_1 +#undef SET_GPIO_CONSTANT_TIM_2 +#undef SET_GPIO_CONSTANT_TIM +#undef SET_GPIO_CONSTANT_CHANNEL +#undef SET_GPIO_CONSTANT +} + +#endif /* ENABLE_MODULE_PWM */ + + +void iotjs_stm32f7nucleo_pin_initialize(jerry_value_t jobj) { + jerry_value_t jpin = jerry_create_object(); + iotjs_jval_set_property_jval(jobj, "pin", jpin); + +#if ENABLE_MODULE_ADC + iotjs_pin_initialize_adc(jpin); +#endif /* ENABLE_MODULE_ADC */ + +#if ENABLE_MODULE_GPIO + iotjs_pin_initialize_gpio(jpin); +#endif /* ENABLE_MODULE_GPIO */ + +#if ENABLE_MODULE_PWM + iotjs_pin_initialize_pwm(jpin); +#endif /* ENABLE_MODULE_PWM */ + + jerry_release_value(jpin); +} + + +#endif // __NUTTX__ diff --git a/src/modules/nuttx/iotjs_module_uart-nuttx.c b/src/modules/nuttx/iotjs_module_uart-nuttx.c new file mode 100644 index 0000000000..e7792a1c71 --- /dev/null +++ b/src/modules/nuttx/iotjs_module_uart-nuttx.c @@ -0,0 +1,100 @@ +/* Copyright 2016-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 "modules/iotjs_module_uart.h" + +#include "iotjs_uv_handle.h" + +struct iotjs_uart_platform_data_s { + iotjs_string_t device_path; +}; + +void iotjs_uart_create_platform_data(iotjs_uart_t* uart) { + uart->platform_data = IOTJS_ALLOC(iotjs_uart_platform_data_t); +} + +void iotjs_uart_destroy_platform_data( + iotjs_uart_platform_data_t* platform_data) { + IOTJS_ASSERT(platform_data); + + iotjs_string_destroy(&platform_data->device_path); + IOTJS_RELEASE(platform_data); +} + +jerry_value_t iotjs_uart_set_platform_config(iotjs_uart_t* uart, + const jerry_value_t jconfig) { + JS_GET_REQUIRED_CONF_VALUE(jconfig, uart->platform_data->device_path, + IOTJS_MAGIC_STRING_DEVICE, string); + + return jerry_create_undefined(); +} + +bool iotjs_uart_open(uv_handle_t* uart_poll_handle) { + iotjs_uart_t* uart = + (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle); + int fd = open(iotjs_string_data(&uart->platform_data->device_path), + O_RDWR | O_NOCTTY | O_NDELAY); + + if (fd < 0) { + return false; + } + + uart->device_fd = fd; + iotjs_uart_register_read_cb((uv_poll_t*)uart); + + return true; +} + +bool iotjs_uart_write(uv_handle_t* uart_poll_handle) { + iotjs_uart_t* uart = + (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle); + int bytesWritten = 0; + unsigned offset = 0; + int fd = uart->device_fd; + const char* buf_data = iotjs_string_data(&uart->buf_data); + + DDDLOG("%s - data: %s", __func__, buf_data); + + do { + errno = 0; + bytesWritten = write(fd, buf_data + offset, uart->buf_len - offset); + + DDDLOG("%s - size: %d", __func__, uart->buf_len - offset); + + if (bytesWritten != -1) { + offset += (unsigned)bytesWritten; + continue; + } + + if (errno == EINTR) { + continue; + } + + return false; + + } while (uart->buf_len > offset); + + return true; +} + +void iotjs_uart_handle_close_cb(uv_handle_t* uart_poll_handle) { + iotjs_uart_t* uart = + (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle); + + if (close(uart->device_fd) < 0) { + DLOG(iotjs_periph_error_str(kUartOpClose)); + IOTJS_ASSERT(0); + } +} diff --git a/src/modules/tizen/iotjs_module_gpio-tizen.c b/src/modules/tizen/iotjs_module_gpio-tizen.c new file mode 100644 index 0000000000..e2834f74bb --- /dev/null +++ b/src/modules/tizen/iotjs_module_gpio-tizen.c @@ -0,0 +1,125 @@ +/* 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. + */ + +#include +#include + +#include "modules/iotjs_module_gpio.h" + +struct iotjs_gpio_platform_data_s { + peripheral_gpio_h peripheral_gpio; +}; + +void iotjs_gpio_create_platform_data(iotjs_gpio_t* gpio) { + gpio->platform_data = IOTJS_ALLOC(iotjs_gpio_platform_data_t); +} + +void iotjs_gpio_destroy_platform_data( + iotjs_gpio_platform_data_t* platform_data) { + IOTJS_RELEASE(platform_data); +} + +bool iotjs_gpio_write(iotjs_gpio_t* gpio) { + int retVal = + peripheral_gpio_write(gpio->platform_data->peripheral_gpio, gpio->value); + return PERIPHERAL_ERROR_NONE == retVal; +} + + +bool iotjs_gpio_read(iotjs_gpio_t* gpio) { + uint32_t value; + int retVal = + peripheral_gpio_read(gpio->platform_data->peripheral_gpio, &value); + if (retVal != PERIPHERAL_ERROR_NONE) { + return false; + } + + gpio->value = (bool)value; + return true; +} + + +bool iotjs_gpio_close(iotjs_gpio_t* gpio) { + peripheral_gpio_close(gpio->platform_data->peripheral_gpio); + return true; +} + + +bool iotjs_gpio_open(iotjs_gpio_t* gpio) { + peripheral_gpio_h _gpio; + int retVal = peripheral_gpio_open((int)gpio->pin, &_gpio); + if (retVal != PERIPHERAL_ERROR_NONE) { + return false; + } + + gpio->platform_data->peripheral_gpio = _gpio; + peripheral_gpio_direction_e _direction; + + if (gpio->direction == kGpioDirectionIn) { + _direction = PERIPHERAL_GPIO_DIRECTION_IN; + } else { + _direction = PERIPHERAL_GPIO_DIRECTION_OUT_INITIALLY_LOW; + } + + retVal = peripheral_gpio_set_direction(_gpio, _direction); + if (retVal != PERIPHERAL_ERROR_NONE) { + return false; + } + + // Mode is not supported by Peripheral API for Tizen + peripheral_gpio_edge_e _edge; + switch (gpio->edge) { + case kGpioEdgeNone: + _edge = PERIPHERAL_GPIO_EDGE_NONE; + break; + case kGpioEdgeRising: + _edge = PERIPHERAL_GPIO_EDGE_RISING; + break; + case kGpioEdgeFalling: + _edge = PERIPHERAL_GPIO_EDGE_FALLING; + break; + case kGpioEdgeBoth: + _edge = PERIPHERAL_GPIO_EDGE_BOTH; + break; + default: + _edge = PERIPHERAL_GPIO_EDGE_NONE; + } + + retVal = peripheral_gpio_set_edge_mode(_gpio, _edge); + if (retVal != PERIPHERAL_ERROR_NONE) { + return false; + } + + return true; +} + + +bool iotjs_gpio_set_direction(iotjs_gpio_t* gpio) { + peripheral_gpio_direction_e direction; + if (gpio->direction == kGpioDirectionIn) { + direction = PERIPHERAL_GPIO_DIRECTION_IN; + } else { + direction = PERIPHERAL_GPIO_DIRECTION_OUT_INITIALLY_LOW; + } + + int ret = peripheral_gpio_set_direction(gpio->platform_data->peripheral_gpio, + direction); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s, Cannot set direction(%d).", __func__, ret); + return false; + } + + return true; +} diff --git a/src/modules/tizen/iotjs_module_i2c-tizen.c b/src/modules/tizen/iotjs_module_i2c-tizen.c new file mode 100644 index 0000000000..434c69a1a3 --- /dev/null +++ b/src/modules/tizen/iotjs_module_i2c-tizen.c @@ -0,0 +1,116 @@ +/* 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 !defined(__TIZEN__) +#error "Module __FILE__ is for Tizen only" +#endif + +#include + +#include "modules/iotjs_module_i2c.h" + + +struct iotjs_i2c_platform_data_s { + int bus; + peripheral_i2c_h i2c_h; +}; + +void iotjs_i2c_create_platform_data(iotjs_i2c_t* i2c) { + i2c->platform_data = IOTJS_ALLOC(iotjs_i2c_platform_data_t); + + i2c->platform_data->i2c_h = NULL; +} + +void iotjs_i2c_destroy_platform_data(iotjs_i2c_platform_data_t* pdata) { + IOTJS_RELEASE(pdata); +} + +jerry_value_t iotjs_i2c_set_platform_config(iotjs_i2c_t* i2c, + const jerry_value_t jconfig) { + iotjs_i2c_platform_data_t* platform_data = i2c->platform_data; + + JS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->bus, + IOTJS_MAGIC_STRING_BUS, number); + + return jerry_create_undefined(); +} + +#define I2C_METHOD_HEADER(arg) \ + iotjs_i2c_platform_data_t* platform_data = arg->platform_data; \ + IOTJS_ASSERT(platform_data); \ + if (!platform_data->i2c_h) { \ + DLOG("%s: I2C is not opened", __func__); \ + return false; \ + } + +bool iotjs_i2c_open(iotjs_i2c_t* i2c) { + iotjs_i2c_platform_data_t* platform_data = i2c->platform_data; + IOTJS_ASSERT(platform_data); + + int ret = peripheral_i2c_open(platform_data->bus, i2c->address, + &platform_data->i2c_h); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s : cannot open(%d)", __func__, ret); + return false; + } + + return true; +} + +bool iotjs_i2c_close(iotjs_i2c_t* i2c) { + I2C_METHOD_HEADER(i2c); + + int ret = peripheral_i2c_close(platform_data->i2c_h); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s : cannot close(%d)", __func__, ret); + return false; + } + + return true; +} + +bool iotjs_i2c_write(iotjs_i2c_t* i2c) { + I2C_METHOD_HEADER(i2c); + + IOTJS_ASSERT(i2c->buf_len > 0); + + int ret = peripheral_i2c_write(platform_data->i2c_h, (uint8_t*)i2c->buf_data, + i2c->buf_len); + + IOTJS_RELEASE(i2c->buf_data); + + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s : cannot write(%d)", __func__, ret); + return false; + } + return true; +} + +bool iotjs_i2c_read(iotjs_i2c_t* i2c) { + I2C_METHOD_HEADER(i2c); + + uint8_t len = i2c->buf_len; + i2c->buf_data = iotjs_buffer_allocate(len); + IOTJS_ASSERT(len > 0); + + int ret = + peripheral_i2c_read(platform_data->i2c_h, (uint8_t*)i2c->buf_data, len); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s : cannot read(%d)", __func__, ret); + return false; + } + + return true; +} diff --git a/src/modules/tizen/iotjs_module_pwm-tizen.c b/src/modules/tizen/iotjs_module_pwm-tizen.c new file mode 100644 index 0000000000..19f2ba300a --- /dev/null +++ b/src/modules/tizen/iotjs_module_pwm-tizen.c @@ -0,0 +1,119 @@ +/* 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 + +#include "modules/iotjs_module_pwm.h" + +struct iotjs_pwm_platform_data_s { + peripheral_pwm_h pwm_h; +}; + +void iotjs_pwm_create_platform_data(iotjs_pwm_t* pwm) { + pwm->platform_data = IOTJS_ALLOC(iotjs_pwm_platform_data_t); + pwm->platform_data->pwm_h = NULL; +} + +void iotjs_pwm_destroy_platform_data(iotjs_pwm_platform_data_t* pdata) { + IOTJS_RELEASE(pdata); +} + +jerry_value_t iotjs_pwm_set_platform_config(iotjs_pwm_t* pwm, + const jerry_value_t jconfig) { + return jerry_create_undefined(); +} + +static bool pwm_set_options(iotjs_pwm_t* pwm) { + iotjs_pwm_platform_data_t* platform_data = pwm->platform_data; + + if (platform_data->pwm_h == NULL) { + DLOG("%s - cannot set options", __func__); + return false; + } + + return iotjs_pwm_set_period(pwm) && iotjs_pwm_set_dutycycle(pwm); +} + +bool iotjs_pwm_open(iotjs_pwm_t* pwm) { + iotjs_pwm_platform_data_t* platform_data = pwm->platform_data; + + int ret = peripheral_pwm_open(0, (int)pwm->pin, &platform_data->pwm_h); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s : cannot open(%d)", __func__, ret); + return false; + } + + return pwm_set_options(pwm); +} + +#define PWM_METHOD_HEADER \ + IOTJS_ASSERT(pwm && pwm->platform_data); \ + iotjs_pwm_platform_data_t* platform_data = pwm->platform_data; \ + if (platform_data->pwm_h == NULL) { \ + DLOG("%s: PWM is not opened", __func__); \ + return false; \ + } + +bool iotjs_pwm_set_period(iotjs_pwm_t* pwm) { + PWM_METHOD_HEADER + + uint32_t period_ns = pwm->period * 1E9; + int ret = peripheral_pwm_set_period(platform_data->pwm_h, period_ns); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s : cannot set period(%d)", __func__, ret); + return false; + } + + return true; +} + +bool iotjs_pwm_set_dutycycle(iotjs_pwm_t* pwm) { + PWM_METHOD_HEADER + + uint32_t duty_cycle_ns = pwm->period * pwm->duty_cycle * 1E9; + int ret = peripheral_pwm_set_duty_cycle(platform_data->pwm_h, duty_cycle_ns); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s : cannot set duty-cycle(%d)", __func__, ret); + return false; + } + + return true; +} + +bool iotjs_pwm_set_enable(iotjs_pwm_t* pwm) { + PWM_METHOD_HEADER + + int ret = peripheral_pwm_set_enabled(platform_data->pwm_h, pwm->enable); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s : cannot set enable(%d)", __func__, ret); + return false; + } + + return true; +} + +bool iotjs_pwm_close(iotjs_pwm_t* pwm) { + PWM_METHOD_HEADER + + int ret = peripheral_pwm_close(platform_data->pwm_h); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s : cannot close(%d)", __func__, ret); + return false; + } + platform_data->pwm_h = NULL; + + return true; +} diff --git a/src/modules/tizen/iotjs_module_spi-tizen.c b/src/modules/tizen/iotjs_module_spi-tizen.c new file mode 100644 index 0000000000..e6147a8fa9 --- /dev/null +++ b/src/modules/tizen/iotjs_module_spi-tizen.c @@ -0,0 +1,153 @@ +/* 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 + +#include "modules/iotjs_module_spi.h" + + +struct iotjs_spi_platform_data_s { + int bus; + peripheral_spi_h spi_h; +}; + +static peripheral_spi_mode_e mode_to_constant(SpiMode mode) { + switch (mode) { + case kSpiMode_0: + return PERIPHERAL_SPI_MODE_0; + case kSpiMode_1: + return PERIPHERAL_SPI_MODE_1; + case kSpiMode_2: + return PERIPHERAL_SPI_MODE_2; + case kSpiMode_3: + return PERIPHERAL_SPI_MODE_3; + default: + IOTJS_ASSERT(!"Invalid SPI mode"); + return PERIPHERAL_SPI_MODE_0; + } +} + +static peripheral_spi_bit_order_e bit_order_to_constant(SpiOrder order) { + switch (order) { + case kSpiOrderLsb: + return PERIPHERAL_SPI_BIT_ORDER_LSB; + case kSpiOrderMsb: + return PERIPHERAL_SPI_BIT_ORDER_MSB; + default: + IOTJS_ASSERT(!"Invalid SPI bitOrder"); + return PERIPHERAL_SPI_BIT_ORDER_MSB; + } +} + +void iotjs_spi_create_platform_data(iotjs_spi_t* spi) { + spi->platform_data = IOTJS_ALLOC(iotjs_spi_platform_data_t); + + spi->platform_data->spi_h = NULL; +} + +void iotjs_spi_destroy_platform_data(iotjs_spi_platform_data_t* platform_data) { + IOTJS_ASSERT(platform_data); + IOTJS_RELEASE(platform_data); +} + +jerry_value_t iotjs_spi_set_platform_config(iotjs_spi_t* spi, + const jerry_value_t jconfig) { + JS_GET_REQUIRED_CONF_VALUE(jconfig, spi->platform_data->bus, + IOTJS_MAGIC_STRING_BUS, number); + + return jerry_create_undefined(); +} + +#define SPI_METHOD_HEADER(arg) \ + iotjs_spi_platform_data_t* platform_data = arg->platform_data; \ + IOTJS_ASSERT(platform_data); \ + if (!platform_data->spi_h) { \ + DLOG("%s: SPI is not opened", __func__); \ + return false; \ + } + +bool iotjs_spi_open(iotjs_spi_t* spi) { + iotjs_spi_platform_data_t* platform_data = spi->platform_data; + + int ret = peripheral_spi_open(platform_data->bus, spi->chip_select, + &platform_data->spi_h); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s: cannot open(%d)", __func__, ret); + return false; + } + + // Set mode + ret = peripheral_spi_set_mode(platform_data->spi_h, + mode_to_constant(spi->mode)); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s: cannot set mode(%d)", __func__, ret); + peripheral_spi_close(platform_data->spi_h); + return false; + } + + // Set bit order + ret = peripheral_spi_set_bit_order(platform_data->spi_h, + bit_order_to_constant(spi->bit_order)); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s: cannot set bit order(%d)", __func__, ret); + peripheral_spi_close(platform_data->spi_h); + return false; + } + + // Set bits per word + ret = peripheral_spi_set_bits_per_word(platform_data->spi_h, + spi->bits_per_word); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s: cannot set bit per word(%d)", __func__, ret); + peripheral_spi_close(platform_data->spi_h); + return false; + } + + // Set maxSpeed + ret = peripheral_spi_set_frequency(platform_data->spi_h, spi->max_speed); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s: cannot set maxSpeed(%d)", __func__, ret); + peripheral_spi_close(platform_data->spi_h); + return false; + } + return true; +} + +bool iotjs_spi_transfer(iotjs_spi_t* spi) { + SPI_METHOD_HEADER(spi) + + int ret = + peripheral_spi_transfer(platform_data->spi_h, (uint8_t*)spi->tx_buf_data, + (uint8_t*)spi->rx_buf_data, spi->buf_len); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s: cannot transfer(%d)", __func__, ret); + return false; + } + + return true; +} + +bool iotjs_spi_close(iotjs_spi_t* spi) { + SPI_METHOD_HEADER(spi) + + int ret = peripheral_spi_close(platform_data->spi_h); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s: cannot close(%d)", __func__, ret); + return false; + } + + platform_data->spi_h = NULL; + return true; +} diff --git a/src/modules/tizen/iotjs_module_tizen-tizen.c b/src/modules/tizen/iotjs_module_tizen-tizen.c new file mode 100644 index 0000000000..e4f7a840d6 --- /dev/null +++ b/src/modules/tizen/iotjs_module_tizen-tizen.c @@ -0,0 +1,273 @@ +/* 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_def.h" +#include "modules/iotjs_module_bridge.h" + +#include +#include + +typedef enum { + IOTJS_ERROR_RESULT_FAILED = INT_MIN, + IOTJS_ERROR_INVALID_PARAMETER, + IOTJS_ERROR_OUT_OF_MEMORY, + IOTJS_ERROR_NONE = 0, +} iotjs_error_t; + +// # tizen app-control +#include +#include +#include +#include + +static iotjs_error_t tizen_send_launch_request(const char* json, + void* hbridge) { + DDDLOG("%s", __func__); + + bundle* b; + int ret; + + ret = bundle_from_json(json, &b); + if (ret != BUNDLE_ERROR_NONE) { + DDLOG("bundle_from_json failed"); + return IOTJS_ERROR_INVALID_PARAMETER; + } + + app_control_h app_control = NULL; + + app_control_create(&app_control); + app_control_import_from_bundle(app_control, b); + + ret = app_control_send_launch_request(app_control, NULL, NULL); + + if (ret != APP_CONTROL_ERROR_NONE) { + DDDLOG("app_control_send_launch_request failed"); + switch (ret) { + case APP_CONTROL_ERROR_INVALID_PARAMETER: + iotjs_bridge_set_err(hbridge, "APP_CONTROL_ERROR_INVALID_PARAMETER"); + break; + case APP_CONTROL_ERROR_OUT_OF_MEMORY: + iotjs_bridge_set_err(hbridge, "APP_CONTROL_ERROR_OUT_OF_MEMORY"); + break; + case APP_CONTROL_ERROR_APP_NOT_FOUND: + iotjs_bridge_set_err(hbridge, "APP_CONTROL_ERROR_APP_NOT_FOUND"); + break; + case APP_CONTROL_ERROR_LAUNCH_REJECTED: + iotjs_bridge_set_err(hbridge, "APP_CONTROL_ERROR_LAUNCH_REJECTED"); + break; + case APP_CONTROL_ERROR_LAUNCH_FAILED: + iotjs_bridge_set_err(hbridge, "APP_CONTROL_ERROR_LAUNCH_FAILED"); + break; + case APP_CONTROL_ERROR_TIMED_OUT: + iotjs_bridge_set_err(hbridge, "APP_CONTROL_ERROR_TIMED_OUT"); + break; + case APP_CONTROL_ERROR_PERMISSION_DENIED: + iotjs_bridge_set_err(hbridge, "APP_CONTROL_ERROR_PERMISSION_DENIED"); + break; + default: + iotjs_bridge_set_err(hbridge, "APP_CONTROL_ERROR_UNKNOWN"); + break; + } + return IOTJS_ERROR_RESULT_FAILED; + } + + bundle_free(b); + app_control_destroy(app_control); + + return IOTJS_ERROR_NONE; +} + + +void iotjs_tizen_app_control_cb(app_control_h app_control, void* user_data) { + DDDLOG("%s", __func__); + + iotjs_environment_t* env = iotjs_environment_get(); + + if (env->state != kRunningMain && env->state != kRunningLoop) { + return; + } + + const char* event_emitter_name = IOTJS_MAGIC_STRING_TIZEN; + const char* event_name = IOTJS_MAGIC_STRING_APP_CONTROL; + + jerry_value_t tizen = iotjs_module_get(event_emitter_name); + jerry_value_t fn = iotjs_jval_get_property(tizen, IOTJS_MAGIC_STRING_EMIT); + + if (jerry_value_is_function(fn) == false) { + DDDLOG("tizen module is not loaded"); + goto exit; + } + + // parse app control + char* json = NULL; + bundle* b = NULL; + + app_control_export_as_bundle(app_control, &b); + + if (BUNDLE_ERROR_NONE != bundle_to_json(b, &json)) { + DDLOG("bundle_to_json failed"); + bundle_free(b); + return; + } + DDDLOG("JSON: %s", json); + + // call emit + jerry_value_t jargv[2] = { jerry_create_string( + (const jerry_char_t*)event_name), + jerry_create_string((const jerry_char_t*)json) }; + + iotjs_invoke_callback(fn, tizen, jargv, 2); + jerry_release_value(jargv[0]); + jerry_release_value(jargv[1]); + + free(json); + bundle_free(b); + +exit: + jerry_release_value(fn); +} + + +// # 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, "getDataPath", strlen("getDataPath")) == 0) { + char* app_data_path = app_get_data_path(); + iotjs_bridge_set_msg(handle, app_data_path); + if (app_data_path != NULL) { + free(app_data_path); + } + } else if (strncmp(command, "launchAppControl", strlen("launchAppControl")) == + 0) { + iotjs_error_t err = tizen_send_launch_request(message, handle); + if (err == IOTJS_ERROR_NONE) { + iotjs_bridge_set_msg(handle, "OK"); + } + + } else { + 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; + } + + jerry_value_t jval = jerry_create_string((const jerry_char_t*)message); + jerry_value_t jres = + iotjs_invoke_callback_with_result(jfunc, jmodule, &jval, 1); + + 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); + jerry_release_value(jval); + 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; +} diff --git a/src/modules/tizen/iotjs_module_uart-tizen.c b/src/modules/tizen/iotjs_module_uart-tizen.c new file mode 100644 index 0000000000..2217180359 --- /dev/null +++ b/src/modules/tizen/iotjs_module_uart-tizen.c @@ -0,0 +1,182 @@ +/* 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 + +#include "iotjs_uv_handle.h" +#include "modules/iotjs_module_uart.h" + +struct _peripheral_uart_s { + unsigned handle; + int fd; +}; + +struct iotjs_uart_platform_data_s { + peripheral_uart_h uart_h; + uint8_t port; +}; + +static peripheral_uart_baud_rate_e baud_to_constant(unsigned baudRate) { + switch (baudRate) { + case 0: + return PERIPHERAL_UART_BAUD_RATE_0; + case 50: + return PERIPHERAL_UART_BAUD_RATE_50; + case 75: + return PERIPHERAL_UART_BAUD_RATE_75; + case 110: + return PERIPHERAL_UART_BAUD_RATE_110; + case 134: + return PERIPHERAL_UART_BAUD_RATE_134; + case 150: + return PERIPHERAL_UART_BAUD_RATE_150; + case 200: + return PERIPHERAL_UART_BAUD_RATE_200; + case 300: + return PERIPHERAL_UART_BAUD_RATE_300; + case 600: + return PERIPHERAL_UART_BAUD_RATE_600; + case 1200: + return PERIPHERAL_UART_BAUD_RATE_1200; + case 1800: + return PERIPHERAL_UART_BAUD_RATE_1800; + case 2400: + return PERIPHERAL_UART_BAUD_RATE_2400; + case 4800: + return PERIPHERAL_UART_BAUD_RATE_4800; + case 9600: + return PERIPHERAL_UART_BAUD_RATE_9600; + case 19200: + return PERIPHERAL_UART_BAUD_RATE_19200; + case 38400: + return PERIPHERAL_UART_BAUD_RATE_38400; + case 57600: + return PERIPHERAL_UART_BAUD_RATE_57600; + case 115200: + return PERIPHERAL_UART_BAUD_RATE_115200; + case 230400: + return PERIPHERAL_UART_BAUD_RATE_230400; + } + + IOTJS_ASSERT(!"Invalid baud rate"); + return -1; +} + +static peripheral_uart_byte_size_e databits_to_constant(uint8_t dataBits) { + switch (dataBits) { + case 8: + return PERIPHERAL_UART_BYTE_SIZE_8BIT; + case 7: + return PERIPHERAL_UART_BYTE_SIZE_7BIT; + case 6: + return PERIPHERAL_UART_BYTE_SIZE_6BIT; + case 5: + return PERIPHERAL_UART_BYTE_SIZE_5BIT; + } + + IOTJS_ASSERT(!"Invalid data bits"); + return -1; +} + +void iotjs_uart_create_platform_data(iotjs_uart_t* uart) { + uart->platform_data = IOTJS_ALLOC(iotjs_uart_platform_data_t); + uart->platform_data->uart_h = NULL; +} + +void iotjs_uart_destroy_platform_data( + iotjs_uart_platform_data_t* platform_data) { + IOTJS_ASSERT(platform_data); + IOTJS_RELEASE(platform_data); +} + +jerry_value_t iotjs_uart_set_platform_config(iotjs_uart_t* uart, + const jerry_value_t jconfig) { + JS_GET_REQUIRED_CONF_VALUE(jconfig, uart->platform_data->port, + IOTJS_MAGIC_STRING_PORT, number); + + return jerry_create_undefined(); +} + +bool iotjs_uart_open(uv_handle_t* uart_poll_handle) { + iotjs_uart_t* uart = + (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle); + iotjs_uart_platform_data_t* platform_data = uart->platform_data; + IOTJS_ASSERT(platform_data); + + int ret = peripheral_uart_open(platform_data->port, &platform_data->uart_h); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s: cannot open(%d)", __func__, ret); + return false; + } + + // Set baud rate + ret = peripheral_uart_set_baud_rate(platform_data->uart_h, + baud_to_constant(uart->baud_rate)); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s: cannot set baud rate(%d)", __func__, ret); + peripheral_uart_close(platform_data->uart_h); + return false; + } + + // Set data bits + ret = peripheral_uart_set_byte_size(platform_data->uart_h, + databits_to_constant(uart->data_bits)); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s: cannot set data bits(%d)", __func__, ret); + peripheral_uart_close(platform_data->uart_h); + return false; + } + + uart->device_fd = platform_data->uart_h->fd; + iotjs_uart_register_read_cb((uv_poll_t*)uart_poll_handle); + + return true; +} + +bool iotjs_uart_write(uv_handle_t* uart_poll_handle) { + iotjs_uart_t* uart = + (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle); + iotjs_uart_platform_data_t* platform_data = uart->platform_data; + IOTJS_ASSERT(platform_data); + if (!platform_data->uart_h) { + DLOG("%s: UART is not opened", __func__); + return false; + } + + const char* buf_data = iotjs_string_data(&uart->buf_data); + DDDLOG("%s: data: %s", __func__, buf_data); + + int ret = peripheral_uart_write(platform_data->uart_h, (uint8_t*)buf_data, + uart->buf_len); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s: cannot write(%d)", __func__, ret); + return false; + } + + return true; +} + +void iotjs_uart_handle_close_cb(uv_handle_t* uart_poll_handle) { + iotjs_uart_t* uart = + (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle); + + if (peripheral_uart_close(uart->platform_data->uart_h) != + PERIPHERAL_ERROR_NONE) { + DLOG("%s: error(%s) ", __func__, iotjs_periph_error_str(kUartOpClose)); + IOTJS_ASSERT(0); + } + + uart->platform_data->uart_h = NULL; +} diff --git a/src/modules/tizenrt/iotjs_module_adc-tizenrt.c b/src/modules/tizenrt/iotjs_module_adc-tizenrt.c new file mode 100644 index 0000000000..2b72c4ec99 --- /dev/null +++ b/src/modules/tizenrt/iotjs_module_adc-tizenrt.c @@ -0,0 +1,135 @@ +/* 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. + */ + +#if !defined(__TIZENRT__) +#error "Module __FILE__ is for TizenRT only" +#endif + +#include +#include +#include +#include +#include +#include + +#include "iotjs_def.h" +#include "modules/iotjs_module_adc.h" + +#define S5J_ADC_MAX_CHANNELS 4 + +struct iotjs_adc_platform_data_s { + int32_t device_fd; + uint32_t pin; +}; + +// There is one file for all ADC inputs so wee need one common file descriptor +static int32_t device_fd; +// This is simple ref counter. Each time ADC is opened, it is increased. +static size_t device_fd_counter = 0; +// Path of ADC device. +#define TIZENRT_ADC_DEVICE "/dev/adc0" + +void iotjs_adc_create_platform_data(iotjs_adc_t* adc) { + adc->platform_data = IOTJS_ALLOC(iotjs_adc_platform_data_t); + adc->platform_data->device_fd = -1; + adc->platform_data->pin = 0; +} + + +void iotjs_adc_destroy_platform_data(iotjs_adc_platform_data_t* platform_data) { + IOTJS_RELEASE(platform_data); +} + + +jerry_value_t iotjs_adc_set_platform_config(iotjs_adc_t* adc, + const jerry_value_t jconfig) { + iotjs_adc_platform_data_t* platform_data = adc->platform_data; + + JS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->pin, + IOTJS_MAGIC_STRING_PIN, number); + + return jerry_create_undefined(); +} + + +bool iotjs_adc_read(iotjs_adc_t* adc) { + iotjs_adc_platform_data_t* platform_data = adc->platform_data; + + int ret, nbytes; + size_t readsize, i, nsamples; + struct adc_msg_s samples[S5J_ADC_MAX_CHANNELS]; + ret = ioctl(platform_data->device_fd, ANIOC_TRIGGER, 0); + + if (ret < 0) { + adc->value = -1; + return false; + } + + readsize = sizeof(samples); + while (true) { + nbytes = read(platform_data->device_fd, samples, readsize); + if (nbytes > 0) { + nsamples = (size_t)nbytes / sizeof(struct adc_msg_s); + int sample = -1; + for (i = 0; i < nsamples; ++i) { + if (platform_data->pin == samples[i].am_channel) { + sample = samples[i].am_data; + } + } + if (sample != -1) { + adc->value = sample; + return true; + } + } /* else { + // The read function is blocking but there are events, + // which can interrupt it. The function will return + // non-positive number of obtained samples. We can ignore it and + // wait for next samples returned from ADC. + } */ + } +} + + +bool iotjs_adc_close(iotjs_adc_t* adc) { + iotjs_adc_platform_data_t* platform_data = adc->platform_data; + + if (platform_data->device_fd > 0) { + device_fd_counter--; + } + + if (device_fd_counter == 0) { + close(platform_data->device_fd); + } + + return true; +} + + +bool iotjs_adc_open(iotjs_adc_t* adc) { + iotjs_adc_platform_data_t* platform_data = adc->platform_data; + + if (device_fd_counter == 0) { + device_fd = open(TIZENRT_ADC_DEVICE, O_RDONLY); + } + + platform_data->device_fd = device_fd; + if (platform_data->device_fd < 0) { + return false; + } + + device_fd_counter++; + + return true; +} diff --git a/src/modules/tizenrt/iotjs_module_gpio-tizenrt.c b/src/modules/tizenrt/iotjs_module_gpio-tizenrt.c new file mode 100644 index 0000000000..965ca847e4 --- /dev/null +++ b/src/modules/tizenrt/iotjs_module_gpio-tizenrt.c @@ -0,0 +1,114 @@ +/* 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. + */ + + +#include +#include + +#include "modules/iotjs_module_gpio.h" + +struct iotjs_gpio_platform_data_s { + iotbus_gpio_context_h gpio_context; +}; + + +void iotjs_gpio_create_platform_data(iotjs_gpio_t* gpio) { + gpio->platform_data = IOTJS_ALLOC(iotjs_gpio_platform_data_t); +} + + +void iotjs_gpio_destroy_platform_data( + iotjs_gpio_platform_data_t* platform_data) { + IOTJS_RELEASE(platform_data); +} + + +bool iotjs_gpio_open(iotjs_gpio_t* gpio) { + DDDLOG("%s - pin: %d, direction: %d, mode: %d", __func__, gpio->pin, + gpio->direction, gpio->mode); + + iotbus_gpio_context_h gpio_context = iotbus_gpio_open((int)gpio->pin); + if (gpio_context == NULL) { + iotbus_gpio_close(gpio_context); + return false; + } + + // Set direction + iotbus_gpio_direction_e direction; + if (gpio->direction == kGpioDirectionIn) { + direction = IOTBUS_GPIO_DIRECTION_IN; + } else if (gpio->direction == kGpioDirectionOut) { + direction = IOTBUS_GPIO_DIRECTION_OUT; + } else { + direction = IOTBUS_GPIO_DIRECTION_NONE; + } + + if (iotbus_gpio_set_direction(gpio_context, direction) < 0) { + iotbus_gpio_close(gpio_context); + return false; + } + + gpio->platform_data->gpio_context = gpio_context; + + return true; +} + + +bool iotjs_gpio_write(iotjs_gpio_t* gpio) { + if (iotbus_gpio_write(gpio->platform_data->gpio_context, gpio->value) < 0) { + return false; + } + return true; +} + + +bool iotjs_gpio_read(iotjs_gpio_t* gpio) { + int ret = iotbus_gpio_read(gpio->platform_data->gpio_context); + if (ret < 0) { + DLOG("%s, Cannot read value(%d).", __func__, ret); + return false; + } + + gpio->value = (bool)ret; + return true; +} + + +bool iotjs_gpio_close(iotjs_gpio_t* gpio) { + if (gpio->platform_data->gpio_context && + iotbus_gpio_close(gpio->platform_data->gpio_context) < 0) { + return false; + } + return true; +} + + +bool iotjs_gpio_set_direction(iotjs_gpio_t* gpio) { + iotbus_gpio_direction_e direction; + if (gpio->direction == kGpioDirectionIn) { + direction = IOTBUS_GPIO_DIRECTION_IN; + } else { + direction = IOTBUS_GPIO_DIRECTION_OUT; + } + + int ret = + iotbus_gpio_set_direction(gpio->platform_data->gpio_context, direction); + if (ret != 0) { + DLOG("%s, Cannot set direction(%d).", __func__, ret); + return false; + } + + return true; +} diff --git a/src/modules/tizenrt/iotjs_module_i2c-tizenrt.c b/src/modules/tizenrt/iotjs_module_i2c-tizenrt.c new file mode 100644 index 0000000000..d899af1eeb --- /dev/null +++ b/src/modules/tizenrt/iotjs_module_i2c-tizenrt.c @@ -0,0 +1,144 @@ +/* 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. + */ + +#if !defined(__TIZENRT__) +#error "Module __FILE__ is for TizenRT only" +#endif + +#include + +#if !defined(CONFIG_I2C) +#error "\n\nTizenRT CONFIG_I2C configuration flag required for I2C module\n\n" +#endif + +#include + +#include "modules/iotjs_module_i2c.h" + + +struct iotjs_i2c_platform_data_s { + int bus; + iotbus_i2c_context_h i2c_context; +}; + + +void iotjs_i2c_create_platform_data(iotjs_i2c_t* i2c) { + i2c->platform_data = IOTJS_ALLOC(iotjs_i2c_platform_data_t); + + i2c->platform_data->i2c_context = NULL; +} + + +void iotjs_i2c_destroy_platform_data(iotjs_i2c_platform_data_t* platform_data) { + IOTJS_ASSERT(platform_data); + IOTJS_RELEASE(platform_data); +} + + +jerry_value_t iotjs_i2c_set_platform_config(iotjs_i2c_t* i2c, + const jerry_value_t jconfig) { + iotjs_i2c_platform_data_t* platform_data = i2c->platform_data; + + JS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->bus, + IOTJS_MAGIC_STRING_BUS, number); + + return jerry_create_undefined(); +} + + +#define I2C_METHOD_HEADER(arg) \ + iotjs_i2c_platform_data_t* platform_data = arg->platform_data; \ + IOTJS_ASSERT(platform_data); \ + if (!platform_data->i2c_context) { \ + DLOG("%s: I2C is not opened", __func__); \ + return false; \ + } + + +bool iotjs_i2c_open(iotjs_i2c_t* i2c) { + iotjs_i2c_platform_data_t* platform_data = i2c->platform_data; + IOTJS_ASSERT(platform_data); + + // Init i2c context + platform_data->i2c_context = iotbus_i2c_init(platform_data->bus); + if (!platform_data->i2c_context) { + DLOG("%s: cannot open I2C", __func__); + return false; + } + + // Set i2c frequency + int ret = + iotbus_i2c_set_frequency(platform_data->i2c_context, IOTBUS_I2C_STD); + if (ret < 0) { + DLOG("%s: cannot set frequency", __func__); + return false; + } + + if (iotbus_i2c_set_address(platform_data->i2c_context, i2c->address) < 0) { + DLOG("%s: cannot set address", __func__); + return false; + } + + return true; +} + + +bool iotjs_i2c_close(iotjs_i2c_t* i2c) { + I2C_METHOD_HEADER(i2c); + + if (iotbus_i2c_stop(platform_data->i2c_context) < 0) { + DLOG("%s: cannot close I2C", __func__); + return false; + } + + return true; +} + + +bool iotjs_i2c_write(iotjs_i2c_t* i2c) { + I2C_METHOD_HEADER(i2c); + + uint8_t len = i2c->buf_len; + IOTJS_ASSERT(len > 0); + uint8_t* data = (uint8_t*)i2c->buf_data; + + int ret = iotbus_i2c_write(platform_data->i2c_context, data, len); + + IOTJS_RELEASE(i2c->buf_data); + + if (ret < 0) { + DLOG("%s: cannot write data", __func__); + return false; + } + return true; +} + + +bool iotjs_i2c_read(iotjs_i2c_t* i2c) { + I2C_METHOD_HEADER(i2c); + + uint8_t len = i2c->buf_len; + i2c->buf_data = iotjs_buffer_allocate(len); + + IOTJS_ASSERT(len > 0); + + if (iotbus_i2c_read(platform_data->i2c_context, (uint8_t*)i2c->buf_data, + len) < 0) { + DLOG("%s: cannot read data", __func__); + return false; + } + + return true; +} diff --git a/src/modules/tizenrt/iotjs_module_pwm-tizenrt.c b/src/modules/tizenrt/iotjs_module_pwm-tizenrt.c new file mode 100644 index 0000000000..863d8e6486 --- /dev/null +++ b/src/modules/tizenrt/iotjs_module_pwm-tizenrt.c @@ -0,0 +1,145 @@ +/* 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. + */ + +#if defined(__TIZENRT__) + +#include +#include + +#include +#include + +#include "modules/iotjs_module_pwm.h" + +struct iotjs_pwm_platform_data_s { + iotbus_pwm_context_h ctx; +}; + +void iotjs_pwm_create_platform_data(iotjs_pwm_t* pwm) { + pwm->platform_data = IOTJS_ALLOC(iotjs_pwm_platform_data_t); +} + +void iotjs_pwm_destroy_platform_data(iotjs_pwm_platform_data_t* pdata) { + IOTJS_RELEASE(pdata); +} + +jerry_value_t iotjs_pwm_set_platform_config(iotjs_pwm_t* pwm, + const jerry_value_t jconfig) { + return jerry_create_undefined(); +} + +static bool pwm_set_options(iotjs_pwm_t* pwm) { + iotjs_pwm_platform_data_t* platform_data = pwm->platform_data; + + if (platform_data->ctx == NULL) { + DLOG("%s - file open failed", __func__); + return false; + } + + DDDLOG("%s - period: %d, duty: %d", __func__, (int)pwm->period, + (int)(pwm->duty_cycle * 100)); + + return iotjs_pwm_set_dutycycle(pwm) && iotjs_pwm_set_period(pwm); +} + +bool iotjs_pwm_open(iotjs_pwm_t* pwm) { + iotjs_pwm_platform_data_t* platform_data = pwm->platform_data; + + platform_data->ctx = iotbus_pwm_open(0, (int)pwm->pin); + if (platform_data->ctx == NULL) { + DLOG("%s - file open failed", __func__); + return false; + } + + if (!pwm_set_options(pwm)) { + return false; + } + + return true; +} + +bool iotjs_pwm_set_period(iotjs_pwm_t* pwm) { + iotjs_pwm_platform_data_t* platform_data = pwm->platform_data; + + iotbus_pwm_context_h ctx = platform_data->ctx; + if (ctx == NULL) { + DLOG("%s - file open failed", __func__); + return false; + } + + uint32_t period_us = (uint32_t)(1000000 * pwm->period); + + return iotbus_pwm_set_period(ctx, period_us) == 0; +} + +bool iotjs_pwm_set_dutycycle(iotjs_pwm_t* pwm) { + iotjs_pwm_platform_data_t* platform_data = pwm->platform_data; + + iotbus_pwm_context_h ctx = platform_data->ctx; + if (ctx == NULL) { + DLOG("%s - file open failed", __func__); + return false; + } + + uint32_t duty_cycle_per_cent = (uint32_t)(pwm->duty_cycle * 100); + + return iotbus_pwm_set_duty_cycle(ctx, duty_cycle_per_cent) == 0; +} + +bool iotjs_pwm_set_enable(iotjs_pwm_t* pwm) { + iotjs_pwm_platform_data_t* platform_data = pwm->platform_data; + + iotbus_pwm_context_h ctx = platform_data->ctx; + if (ctx == NULL) { + DLOG("%s - file open failed", __func__); + return false; + } + + DDDLOG("%s - enable: %d", __func__, pwm->enable); + + int ret; + if (pwm->enable) { + ret = iotbus_pwm_set_enabled(ctx, IOTBUS_PWM_ENABLE); + } else { + ret = iotbus_pwm_set_enabled(ctx, IOTBUS_PWM_DISABLE); + } + + if (ret < 0) { + DLOG("%s - setEnable failed", __func__); + return false; + } + + return true; +} + +bool iotjs_pwm_close(iotjs_pwm_t* pwm) { + iotjs_pwm_platform_data_t* platform_data = pwm->platform_data; + + iotbus_pwm_context_h ctx = platform_data->ctx; + if (ctx == NULL) { + DLOG("%s - file not opened", __func__); + return false; + } + + DDDLOG("%s", __func__); + + iotbus_pwm_close(ctx); + platform_data->ctx = NULL; + + return true; +} + + +#endif // __TIZENRT__ diff --git a/src/modules/tizenrt/iotjs_module_spi-tizenrt.c b/src/modules/tizenrt/iotjs_module_spi-tizenrt.c new file mode 100644 index 0000000000..11f91d8ec9 --- /dev/null +++ b/src/modules/tizenrt/iotjs_module_spi-tizenrt.c @@ -0,0 +1,130 @@ +/* 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. + */ + +#if !defined(__TIZENRT__) +#error "Module __FILE__ is for TizenRT only" +#endif + +#include + +#if !defined(CONFIG_SPI) +#error "\n\nTizenRT CONFIG_SPI configuration flag required for SPI module\n\n" +#elif !defined(CONFIG_SPI_EXCHANGE) +#error "\n\nTizenRT CONFIG_SPI_EXCHANGE flag required for SPI module\n\n" +#endif + +#include +#include + +#include "modules/iotjs_module_spi.h" + + +struct iotjs_spi_platform_data_s { + unsigned int bus; + iotbus_spi_context_h spi_context; +}; + +void iotjs_spi_create_platform_data(iotjs_spi_t* spi) { + spi->platform_data = IOTJS_ALLOC(iotjs_spi_platform_data_t); + + spi->platform_data->spi_context = NULL; +} + + +void iotjs_spi_destroy_platform_data(iotjs_spi_platform_data_t* platform_data) { + IOTJS_ASSERT(platform_data); + IOTJS_RELEASE(platform_data); +} + + +jerry_value_t iotjs_spi_set_platform_config(iotjs_spi_t* spi, + const jerry_value_t jconfig) { + iotjs_spi_platform_data_t* platform_data = spi->platform_data; + + JS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->bus, + IOTJS_MAGIC_STRING_BUS, number); + + return jerry_create_undefined(); +} + +bool iotjs_spi_open(iotjs_spi_t* spi) { + iotjs_spi_platform_data_t* platform_data = spi->platform_data; + + struct iotbus_spi_config_s cfg = {.bits_per_word = spi->bits_per_word, + .chip_select = spi->chip_select, + .frequency = spi->max_speed }; + + switch (spi->mode) { + case kSpiMode_0: + cfg.mode = IOTBUS_SPI_MODE0; + break; + case kSpiMode_1: + cfg.mode = IOTBUS_SPI_MODE1; + break; + case kSpiMode_2: + cfg.mode = IOTBUS_SPI_MODE2; + break; + case kSpiMode_3: + cfg.mode = IOTBUS_SPI_MODE3; + break; + default: + cfg.mode = IOTBUS_SPI_MODE0; + } + + platform_data->spi_context = iotbus_spi_open(platform_data->bus, &cfg); + if (platform_data->spi_context == NULL) { + return false; + } + + DDLOG( + "SPI Options \n mode: %d\n chipSelect: %d\n bitOrder: %d\n " + "maxSpeed: %d\n bitPerWord: %d\n loopback: %d", + spi->mode, spi->chip_select, spi->bit_order, spi->max_speed, + spi->bits_per_word, spi->loopback); + + return true; +} + + +bool iotjs_spi_transfer(iotjs_spi_t* spi) { + iotjs_spi_platform_data_t* platform_data = spi->platform_data; + + int err = + iotbus_spi_transfer_buf(platform_data->spi_context, + (unsigned char*)spi->tx_buf_data, + (unsigned char*)spi->rx_buf_data, spi->buf_len); + if (err != 0) { + DDLOG("%s - transfer failed: %d", __func__, err); + return false; + } + + return true; +} + + +bool iotjs_spi_close(iotjs_spi_t* spi) { + iotjs_spi_platform_data_t* platform_data = spi->platform_data; + + if (platform_data->spi_context != NULL) { + int err = iotbus_spi_close(platform_data->spi_context); + if (err != 0) { + DDLOG("%s - close failed: %d", __func__, err); + return false; + } + platform_data->spi_context = NULL; + } + + return true; +} diff --git a/src/modules/tizenrt/iotjs_module_uart-tizenrt.c b/src/modules/tizenrt/iotjs_module_uart-tizenrt.c new file mode 100644 index 0000000000..08b0c2c50f --- /dev/null +++ b/src/modules/tizenrt/iotjs_module_uart-tizenrt.c @@ -0,0 +1,104 @@ +/* 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. + */ + +#if !defined(__TIZENRT__) +#error "Module __FILE__ is for TizenRT only" +#endif + +#include "modules/iotjs_module_uart.h" + +#include "iotjs_uv_handle.h" + +struct iotjs_uart_platform_data_s { + iotjs_string_t device_path; +}; + +void iotjs_uart_create_platform_data(iotjs_uart_t* uart) { + uart->platform_data = IOTJS_ALLOC(iotjs_uart_platform_data_t); +} + +void iotjs_uart_destroy_platform_data( + iotjs_uart_platform_data_t* platform_data) { + IOTJS_ASSERT(platform_data); + + iotjs_string_destroy(&platform_data->device_path); + IOTJS_RELEASE(platform_data); +} + +jerry_value_t iotjs_uart_set_platform_config(iotjs_uart_t* uart, + const jerry_value_t jconfig) { + JS_GET_REQUIRED_CONF_VALUE(jconfig, uart->platform_data->device_path, + IOTJS_MAGIC_STRING_DEVICE, string); + + return jerry_create_undefined(); +} + +bool iotjs_uart_open(uv_handle_t* uart_poll_handle) { + iotjs_uart_t* uart = + (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle); + int fd = open(iotjs_string_data(&uart->platform_data->device_path), + O_RDWR | O_NOCTTY | O_NDELAY); + + if (fd < 0) { + return false; + } + + uart->device_fd = fd; + iotjs_uart_register_read_cb((uv_poll_t*)uart_poll_handle); + + return true; +} + +bool iotjs_uart_write(uv_handle_t* uart_poll_handle) { + iotjs_uart_t* uart = + (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle); + int bytesWritten = 0; + unsigned offset = 0; + int fd = uart->device_fd; + const char* buf_data = iotjs_string_data(&uart->buf_data); + + DDDLOG("%s - data: %s", __func__, buf_data); + + do { + errno = 0; + bytesWritten = write(fd, buf_data + offset, uart->buf_len - offset); + + DDDLOG("%s - size: %d", __func__, uart->buf_len - offset); + + if (bytesWritten != -1) { + offset += (unsigned)bytesWritten; + continue; + } + + if (errno == EINTR) { + continue; + } + + return false; + + } while (uart->buf_len > offset); + + return true; +} + +void iotjs_uart_handle_close_cb(uv_handle_t* uart_poll_handle) { + iotjs_uart_t* uart = + (iotjs_uart_t*)IOTJS_UV_HANDLE_EXTRA_DATA(uart_poll_handle); + + if (close(uart->device_fd) < 0) { + DLOG(iotjs_periph_error_str(kUartOpClose)); + IOTJS_ASSERT(0); + } +} diff --git a/src/napi/node_api.c b/src/napi/node_api.c new file mode 100644 index 0000000000..182558c192 --- /dev/null +++ b/src/napi/node_api.c @@ -0,0 +1,45 @@ +/* Copyright 2018-present Rokid 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 "jerryscript-ext/handle-scope.h" +#include "jerryscript.h" +#include "internal/node_api_internal.h" + +static napi_node_version node_version = { + .major = NODE_MAJOR_VERSION, + .minor = NODE_MINOR_VERSION, + .patch = NODE_PATCH_VERSION, +}; + +napi_status napi_get_node_version(napi_env env, + const napi_node_version** version) { + NAPI_TRY_ENV(env); + NAPI_ASSIGN(version, &node_version); + NAPI_RETURN(napi_ok); +} + +napi_status napi_get_version(napi_env env, uint32_t* result) { + NAPI_TRY_ENV(env); + NAPI_ASSIGN(result, NAPI_VERSION); + NAPI_RETURN(napi_ok); +} + +napi_status napi_get_uv_event_loop(napi_env env, uv_loop_t** loop) { + NAPI_TRY_ENV(env); + iotjs_environment_t* iotjs_env = iotjs_environment_get(); + uv_loop_t* iotjs_loop = iotjs_environment_loop(iotjs_env); + NAPI_ASSIGN(loop, iotjs_loop); + NAPI_RETURN(napi_ok); +} diff --git a/src/napi/node_api_async.c b/src/napi/node_api_async.c new file mode 100644 index 0000000000..a17f947865 --- /dev/null +++ b/src/napi/node_api_async.c @@ -0,0 +1,169 @@ +/* Copyright 2019-present Samsung Electronics Co., Ltd. and other contributors + * Copyright 2018-present Rokid 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 "uv.h" +#include "internal/node_api_internal.h" + +static void iotjs_uv_work_cb(uv_work_t* req) { + iotjs_async_work_t* async_work = (iotjs_async_work_t*)req->data; + IOTJS_ASSERT(async_work != NULL); + if (async_work->execute != NULL) { + async_work->execute(async_work->env, async_work->data); + } +} + +static void iotjs_uv_work_after_cb(uv_work_t* req, int status) { + iotjs_async_work_t* async_work = (iotjs_async_work_t*)req->data; + IOTJS_ASSERT(async_work != NULL); + napi_status cb_status; + if (status == 0) { + cb_status = napi_ok; + } else if (status == UV_ECANCELED) { + cb_status = napi_cancelled; + } else { + cb_status = napi_generic_failure; + } + + napi_env env = async_work->env; + napi_async_complete_callback complete = async_work->complete; + void* data = async_work->data; + + if (complete != NULL) { + jerryx_handle_scope scope; + jerryx_open_handle_scope(&scope); + /** + * napi_async_work could be deleted by invocation of `napi_delete_asyncwork` + * in its complete callback. + */ + complete(env, cb_status, data); + jerryx_close_handle_scope(scope); + + if (iotjs_napi_is_exception_pending(env)) { + jerry_value_t jval_err; + jval_err = iotjs_napi_env_get_and_clear_exception(env); + if (jval_err == (uintptr_t)NULL) { + jval_err = iotjs_napi_env_get_and_clear_fatal_exception(env); + } + + /** Argument cannot have error flag */ + iotjs_uncaught_exception(jerry_get_value_from_error(jval_err, false)); + jerry_release_value(jval_err); + } + } + + iotjs_process_next_tick(); +} + +napi_status napi_create_async_work(napi_env env, napi_value async_resource, + napi_value async_resource_name, + napi_async_execute_callback execute, + napi_async_complete_callback complete, + void* data, napi_async_work* result) { + NAPI_TRY_ENV(env); + NAPI_WEAK_ASSERT(napi_invalid_arg, result != NULL); + NAPI_WEAK_ASSERT(napi_invalid_arg, execute != NULL); + NAPI_WEAK_ASSERT(napi_invalid_arg, complete != NULL); + + iotjs_async_work_t* async_work = IOTJS_ALLOC(iotjs_async_work_t); + uv_work_t* work_req = &async_work->work_req; + + async_work->env = env; + async_work->async_resource = async_resource; + async_work->async_resource_name = async_resource_name; + async_work->execute = execute; + async_work->complete = complete; + async_work->data = data; + + work_req->data = async_work; + + NAPI_ASSIGN(result, (napi_async_work)work_req); + NAPI_RETURN(napi_ok); +} + +napi_status napi_delete_async_work(napi_env env, napi_async_work work) { + NAPI_TRY_ENV(env); + uv_work_t* work_req = (uv_work_t*)work; + iotjs_async_work_t* async_work = (iotjs_async_work_t*)work_req->data; + IOTJS_RELEASE(async_work); + NAPI_RETURN(napi_ok); +} + +napi_status napi_queue_async_work(napi_env env, napi_async_work work) { + NAPI_TRY_ENV(env); + iotjs_environment_t* iotjs_env = iotjs_environment_get(); + uv_loop_t* loop = iotjs_environment_loop(iotjs_env); + + uv_work_t* work_req = (uv_work_t*)work; + + int status = + uv_queue_work(loop, work_req, iotjs_uv_work_cb, iotjs_uv_work_after_cb); + if (status != 0) { + const char* err_name = uv_err_name(status); + NAPI_RETURN_WITH_MSG(napi_generic_failure, err_name); + } + NAPI_RETURN(napi_ok); +} + +napi_status napi_cancel_async_work(napi_env env, napi_async_work work) { + NAPI_TRY_ENV(env); + uv_work_t* work_req = (uv_work_t*)work; + int status = uv_cancel((uv_req_t*)work_req); + if (status != 0) { + const char* err_name = uv_err_name(status); + NAPI_RETURN_WITH_MSG(napi_generic_failure, err_name); + } + NAPI_RETURN(napi_ok); +} + +napi_status napi_async_init(napi_env env, napi_value async_resource, + napi_value async_resource_name, + napi_async_context* result) { + NAPI_TRY_ENV(env); + + iotjs_async_context_t* ctx = IOTJS_ALLOC(iotjs_async_context_t); + ctx->env = env; + ctx->async_resource = async_resource; + ctx->async_resource_name = async_resource_name; + + NAPI_ASSIGN(result, (napi_async_context)ctx); + return napi_ok; +} + +napi_status napi_async_destroy(napi_env env, napi_async_context async_context) { + NAPI_TRY_ENV(env); + + iotjs_async_context_t* ctx = (iotjs_async_context_t*)async_context; + IOTJS_RELEASE(ctx); + + return napi_ok; +} + +napi_status napi_make_callback(napi_env env, napi_async_context async_context, + napi_value recv, napi_value func, size_t argc, + const napi_value* argv, napi_value* result) { + NAPI_TRY_ENV(env); + + napi_status status = napi_call_function(env, recv, func, argc, argv, result); + if (!iotjs_napi_is_exception_pending(env)) { + iotjs_process_next_tick(); + } else { + // In this case explicit napi_async_destroy calls won't be executed, so + // free the context manually. + IOTJS_RELEASE(async_context); + } + + return status; +} diff --git a/src/napi/node_api_env.c b/src/napi/node_api_env.c new file mode 100644 index 0000000000..3c5ba3d3a0 --- /dev/null +++ b/src/napi/node_api_env.c @@ -0,0 +1,227 @@ +/* Copyright 2019-present Samsung Electronics Co., Ltd. and other contributors + * Copyright 2018-present Rokid 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_def.h" +#include +#include "internal/node_api_internal.h" + +#ifndef NAPI_FATAL_BACKTRACE_LEN +#define NAPI_FATAL_BACKTRACE_LEN 10 +#endif + +static const char* NAPI_GENERIC_ERROR_MESSAGE = "Unexpected error."; + +static iotjs_napi_env_t current_env = { + .pending_exception = NULL, .pending_fatal_exception = NULL, +}; + +napi_env iotjs_get_current_napi_env(void) { + return (napi_env)¤t_env; +} + +static uv_thread_t* iotjs_get_napi_env_thread(napi_env env) { + return &((iotjs_napi_env_t*)env)->main_thread; +} + +bool napi_try_env_helper(napi_env env) { + uv_thread_t current = uv_thread_self(); + IOTJS_ASSERT(uv_thread_equal(iotjs_get_napi_env_thread(env), ¤t)); + return (env != iotjs_get_current_napi_env()); +} + +bool iotjs_napi_is_exception_pending(napi_env env) { + iotjs_napi_env_t* curr_env = (iotjs_napi_env_t*)env; + return !(curr_env->pending_exception == NULL && + curr_env->pending_fatal_exception == NULL); +} + +void iotjs_napi_set_current_callback(napi_env env, + iotjs_callback_info_t* callback_info) { + iotjs_napi_env_t* curr_env = (iotjs_napi_env_t*)env; + curr_env->current_callback_info = callback_info; +} + +iotjs_callback_info_t* iotjs_napi_get_current_callback(napi_env env) { + iotjs_napi_env_t* curr_env = (iotjs_napi_env_t*)env; + return curr_env->current_callback_info; +} + +void iotjs_napi_set_error_info(napi_env env, napi_status error_code, + const char* error_message, + uint32_t engine_error_code, + void* engine_reserved) { + iotjs_napi_env_t* cur_env = (iotjs_napi_env_t*)env; + + if (error_message == NULL && error_code != napi_ok) { + error_message = NAPI_GENERIC_ERROR_MESSAGE; + } + + cur_env->extended_error_info.error_code = error_code; + cur_env->extended_error_info.error_message = error_message; + cur_env->extended_error_info.engine_error_code = engine_error_code; + cur_env->extended_error_info.engine_reserved = engine_reserved; +} + +void iotjs_napi_clear_error_info(napi_env env) { + iotjs_napi_env_t* cur_env = (iotjs_napi_env_t*)env; + + cur_env->extended_error_info.error_code = napi_ok; + cur_env->extended_error_info.error_message = NULL; + cur_env->extended_error_info.engine_error_code = 0; + cur_env->extended_error_info.engine_reserved = NULL; +} + +jerry_value_t iotjs_napi_env_get_and_clear_exception(napi_env env) { + iotjs_napi_env_t* cur_env = (iotjs_napi_env_t*)env; + + jerry_value_t jval_ret = AS_JERRY_VALUE(cur_env->pending_exception); + cur_env->pending_exception = NULL; + + return jval_ret; +} + +jerry_value_t iotjs_napi_env_get_and_clear_fatal_exception(napi_env env) { + iotjs_napi_env_t* cur_env = (iotjs_napi_env_t*)env; + + jerry_value_t jval_ret = AS_JERRY_VALUE(cur_env->pending_fatal_exception); + cur_env->pending_fatal_exception = NULL; + + return jval_ret; +} + +// Methods to support error handling +napi_status napi_throw(napi_env env, napi_value error) { + NAPI_TRY_ENV(env); + iotjs_napi_env_t* curr_env = (iotjs_napi_env_t*)env; + NAPI_TRY_NO_PENDING_EXCEPTION(env); + + jerry_value_t jval_err = AS_JERRY_VALUE(error); + /** + * `jerry_value_set_error_flag` creates a new error reference and its + * reference count is separated from its original value, so we have to + * acquire the original value before `jerry_value_set_error_flag` + */ + jval_err = jerry_acquire_value(jval_err); + + if (!jerry_value_is_error(jval_err)) { + jval_err = jerry_create_error_from_value(jval_err, true); + } + + curr_env->pending_exception = AS_NAPI_VALUE(jval_err); + /** should not clear last error info */ + return napi_ok; +} + +static napi_status napi_throw_helper(jerry_error_t jerry_error_type, + napi_env env, const char* code, + const char* msg) { + NAPI_TRY_ENV(env); + NAPI_TRY_NO_PENDING_EXCEPTION(env); + + jerry_value_t jval_error = + jerry_create_error(jerry_error_type, (jerry_char_t*)msg); + if (code != NULL) { + jval_error = jerry_get_value_from_error(jval_error, true); + iotjs_jval_set_property_string_raw(jval_error, "code", code); + jval_error = jerry_create_error_from_value(jval_error, true); + } + jerryx_create_handle(jval_error); + return napi_throw(env, AS_NAPI_VALUE(jval_error)); +} + +#define DEF_NAPI_THROWS(type, jerry_error_type) \ + napi_status napi_throw_##type(napi_env env, const char* code, \ + const char* msg) { \ + return napi_throw_helper(jerry_error_type, env, code, msg); \ + } + +DEF_NAPI_THROWS(error, JERRY_ERROR_COMMON); +DEF_NAPI_THROWS(type_error, JERRY_ERROR_TYPE); +DEF_NAPI_THROWS(range_error, JERRY_ERROR_RANGE); +#undef DEF_NAPI_THROWS + +// This method invokes an 'uncaughtException', only when jerry-debugger is off +napi_status napi_fatal_exception(napi_env env, napi_value err) { + NAPI_TRY_ENV(env); + NAPI_TRY_NO_PENDING_EXCEPTION(env); + iotjs_napi_env_t* curr_env = (iotjs_napi_env_t*)env; + + jerry_value_t jval_err = AS_JERRY_VALUE(err); + /** + * `jerry_value_set_error_flag` creates a new error reference and its + * reference count is separated from its original value, so we have to + * acquire the original value before `jerry_value_set_error_flag` + */ + jval_err = jerry_acquire_value(jval_err); + + if (!jerry_value_is_abort(jval_err)) { + jval_err = jerry_create_abort_from_value(jval_err, true); + } + + curr_env->pending_fatal_exception = AS_NAPI_VALUE(jval_err); + /** should not clear last error info */ + return napi_ok; +} + +// Methods to support catching exceptions +napi_status napi_is_exception_pending(napi_env env, bool* result) { + NAPI_TRY_ENV(env); + NAPI_ASSIGN(result, iotjs_napi_is_exception_pending(env)); + /** should not clear last error info */ + return napi_ok; +} + +napi_status napi_get_and_clear_last_exception(napi_env env, + napi_value* result) { + NAPI_TRY_ENV(env); + iotjs_napi_env_t* curr_env = (iotjs_napi_env_t*)env; + + napi_value error; + if (curr_env->pending_exception != NULL) { + error = curr_env->pending_exception; + curr_env->pending_exception = NULL; + } else if (curr_env->pending_fatal_exception != NULL) { + error = curr_env->pending_fatal_exception; + curr_env->pending_fatal_exception = NULL; + } else { + error = AS_NAPI_VALUE(jerry_create_undefined()); + } + + jerry_value_t jval_err = + jerry_get_value_from_error(AS_JERRY_VALUE(error), true); + + NAPI_ASSIGN(result, AS_NAPI_VALUE(jval_err)); + /** should not clear last error info */ + return napi_ok; +} + +napi_status napi_get_last_error_info(napi_env env, + const napi_extended_error_info** result) { + NAPI_TRY_ENV(env); + iotjs_napi_env_t* curr_env = (iotjs_napi_env_t*)env; + napi_extended_error_info* error_info = &curr_env->extended_error_info; + + NAPI_ASSIGN(result, error_info); + return napi_ok; +} + +void napi_fatal_error(const char* location, size_t location_len, + const char* message, size_t message_len) { + fprintf(stderr, "FATAL ERROR: %.*s %.*s\n", location_len, location, + message_len, message); + print_stacktrace(); + abort(); +} diff --git a/src/napi/node_api_function.c b/src/napi/node_api_function.c new file mode 100644 index 0000000000..4337cd7830 --- /dev/null +++ b/src/napi/node_api_function.c @@ -0,0 +1,205 @@ +/* Copyright 2019-present Samsung Electronics Co., Ltd. and other contributors + * Copyright 2018-present Rokid 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 "jerryscript-ext/handle-scope.h" +#include "jerryscript.h" +#include +#include "internal/node_api_internal.h" +#include "node_api.h" + +static jerry_value_t iotjs_napi_function_handler( + const jerry_value_t func_obj, const jerry_value_t this_val, + const jerry_value_t args_p[], const jerry_length_t args_cnt) { + iotjs_function_info_t* function_info = (iotjs_function_info_t*) + iotjs_try_get_object_native_info(func_obj, sizeof(iotjs_function_info_t)); + IOTJS_ASSERT(function_info != NULL); + + napi_env env = function_info->env; + + jerryx_handle_scope scope; + jerryx_open_handle_scope(&scope); + + iotjs_callback_info_t* callback_info = IOTJS_ALLOC(iotjs_callback_info_t); + callback_info->argc = args_cnt; + callback_info->argv = (jerry_value_t*)args_p; + callback_info->jval_this = this_val; + callback_info->jval_func = func_obj; + callback_info->function_info = function_info; + + callback_info->handle_scope = scope; + callback_info->function_info = function_info; + + iotjs_napi_set_current_callback(env, callback_info); + napi_value nvalue_ret = + function_info->cb(env, (napi_callback_info)callback_info); + iotjs_napi_set_current_callback(env, NULL); + IOTJS_RELEASE(callback_info); + + jerry_value_t jval_ret; + if (iotjs_napi_is_exception_pending(env)) { + jerry_value_t jval_err = iotjs_napi_env_get_and_clear_exception(env); + if (jval_err != (uintptr_t)NULL) { + jval_ret = jval_err; + } else { + jval_err = iotjs_napi_env_get_and_clear_fatal_exception(env); + IOTJS_ASSERT(jval_err != (uintptr_t)NULL); + + jval_ret = jval_err; + } + + goto cleanup; + } + + // TODO: check if nvalue_ret is escaped + /** + * Do not turn NULL pointer into undefined since number value `0` in + * jerryscript also represented by NULL + */ + jval_ret = AS_JERRY_VALUE(nvalue_ret); + /** + * - for N-API created value: value is scoped, would be released on :cleanup + * - for passed-in params: value would be automatically release on end of + * invocation + * - for error values: error values has been acquired on thrown + */ + jval_ret = jerry_acquire_value(jval_ret); + +cleanup: + jerryx_close_handle_scope(scope); + /** + * Clear N-API env extended error info on end of external function + * execution to prevent error info been passed to next external function. + */ + iotjs_napi_clear_error_info(env); + return jval_ret; +} + +napi_status napi_create_function(napi_env env, const char* utf8name, + size_t length, napi_callback cb, void* data, + napi_value* result) { + NAPI_TRY_ENV(env); + jerry_value_t jval_func = + jerry_create_external_function(iotjs_napi_function_handler); + jerryx_create_handle(jval_func); + + iotjs_function_info_t* function_info = (iotjs_function_info_t*) + iotjs_get_object_native_info(jval_func, sizeof(iotjs_function_info_t)); + function_info->env = env; + function_info->cb = cb; + function_info->data = data; + + return napi_assign_nvalue(jval_func, result); +} + +napi_status napi_call_function(napi_env env, napi_value recv, napi_value func, + size_t argc, const napi_value* argv, + napi_value* result) { + NAPI_TRY_ENV(env); + NAPI_TRY_NO_PENDING_EXCEPTION(env); + + jerry_value_t jval_func = AS_JERRY_VALUE(func); + jerry_value_t jval_this = AS_JERRY_VALUE(recv); + + NAPI_TRY_TYPE(function, jval_func); + + jerry_value_t* jval_argv = IOTJS_CALLOC(argc, jerry_value_t); + for (size_t idx = 0; idx < argc; ++idx) { + jval_argv[idx] = AS_JERRY_VALUE(argv[idx]); + } + JERRYX_CREATE(jval_ret, + jerry_call_function(jval_func, jval_this, jval_argv, argc)); + IOTJS_RELEASE(jval_argv); + + if (jerry_value_is_error(jval_ret)) { + NAPI_INTERNAL_CALL(napi_throw(env, AS_NAPI_VALUE(jval_ret))); + NAPI_RETURN_WITH_MSG(napi_pending_exception, + "Unexpected error flag on jerry_call_function."); + } + + return napi_assign_nvalue(jval_ret, result); +} + +napi_status napi_get_cb_info(napi_env env, napi_callback_info cbinfo, + size_t* argc, napi_value* argv, + napi_value* thisArg, void** data) { + NAPI_TRY_ENV(env); + iotjs_callback_info_t* callback_info = (iotjs_callback_info_t*)cbinfo; + + size_t _argc = (argc == NULL || argv == NULL) ? 0 : *argc; + for (size_t i = 0; i < _argc; ++i) { + if (i < callback_info->argc) { + NAPI_ASSIGN(argv + i, AS_NAPI_VALUE(callback_info->argv[i])); + } else { + NAPI_ASSIGN(argv + i, AS_NAPI_VALUE(jerry_create_undefined())); + } + } + NAPI_ASSIGN(argc, callback_info->argc); + + if (thisArg != NULL) { + NAPI_ASSIGN(thisArg, AS_NAPI_VALUE(callback_info->jval_this)); + } + + if (data != NULL) { + NAPI_ASSIGN(data, callback_info->function_info->data); + } + + NAPI_RETURN(napi_ok); +} + +napi_status napi_get_new_target(napi_env env, napi_callback_info cbinfo, + napi_value* result) { + iotjs_callback_info_t* callback_info = (iotjs_callback_info_t*)cbinfo; + jerry_value_t jval_this = callback_info->jval_this; + jerry_value_t jval_target = callback_info->jval_func; + jerry_value_t is_instance = + jerry_binary_operation(JERRY_BIN_OP_INSTANCEOF, jval_this, jval_target); + if (jerry_value_is_error(is_instance)) { + jerry_release_value(is_instance); + NAPI_ASSIGN(result, NULL); + NAPI_RETURN(napi_generic_failure); + } + + NAPI_ASSIGN(result, jerry_get_boolean_value(is_instance) + ? AS_NAPI_VALUE(jval_target) + : NULL); + NAPI_RETURN(napi_ok); +} + +napi_status napi_new_instance(napi_env env, napi_value constructor, size_t argc, + const napi_value* argv, napi_value* result) { + NAPI_TRY_ENV(env); + NAPI_TRY_NO_PENDING_EXCEPTION(env); + + jerry_value_t jval_cons = AS_JERRY_VALUE(constructor); + + NAPI_TRY_TYPE(function, jval_cons); + + jerry_value_t* jval_argv = IOTJS_CALLOC(argc, jerry_value_t); + for (size_t idx = 0; idx < argc; ++idx) { + jval_argv[idx] = AS_JERRY_VALUE(argv[idx]); + } + + JERRYX_CREATE(jval_ret, jerry_construct_object(jval_cons, jval_argv, argc)); + IOTJS_RELEASE(jval_argv); + + if (jerry_value_is_error(jval_ret)) { + NAPI_INTERNAL_CALL(napi_throw(env, AS_NAPI_VALUE(jval_ret))); + NAPI_RETURN_WITH_MSG(napi_pending_exception, + "Unexpected error flag on jerry_construct_object."); + } + + return napi_assign_nvalue(jval_ret, result); +} diff --git a/src/napi/node_api_lifetime.c b/src/napi/node_api_lifetime.c new file mode 100644 index 0000000000..1666d8507f --- /dev/null +++ b/src/napi/node_api_lifetime.c @@ -0,0 +1,307 @@ +/* Copyright 2018-present Rokid 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 "jerryscript-ext/handle-scope.h" +#include +#include "internal/node_api_internal.h" + +IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(object_info); + +static void iotjs_object_info_destroy(iotjs_object_info_t* info) { + iotjs_reference_t* comp = info->ref_start; + while (comp != NULL) { + comp->jval = jerry_create_undefined(); + comp = comp->next; + } + + if (info->finalize_cb != NULL) { + info->finalize_cb(info->env, info->native_object, info->finalize_hint); + } + + IOTJS_RELEASE(info); +} + +inline napi_status jerryx_status_to_napi_status( + jerryx_handle_scope_status status) { + switch (status) { + case jerryx_handle_scope_mismatch: + NAPI_RETURN(napi_handle_scope_mismatch); + case jerryx_escape_called_twice: + NAPI_RETURN(napi_escape_called_twice); + default: + NAPI_RETURN(napi_ok); + } +} + +iotjs_object_info_t* iotjs_get_object_native_info(jerry_value_t jval, + size_t native_info_size) { + void* info; + if (!jerry_get_object_native_pointer(jval, &info, &this_module_native_info)) { + info = iotjs_buffer_allocate(native_info_size); + jerry_set_object_native_pointer(jval, info, &this_module_native_info); + } + + return (iotjs_object_info_t*)info; +} + +iotjs_object_info_t* iotjs_try_get_object_native_info(jerry_value_t jval, + size_t native_info_size) { + void* info = NULL; + if (jerry_get_object_native_pointer(jval, &info, &this_module_native_info)) { + return (iotjs_object_info_t*)info; + } + + return NULL; +} + +napi_status napi_open_handle_scope(napi_env env, napi_handle_scope* result) { + NAPI_TRY_ENV(env); + NAPI_WEAK_ASSERT(napi_invalid_arg, result != NULL); + + jerryx_handle_scope_status status; + status = jerryx_open_handle_scope((jerryx_handle_scope*)result); + + return jerryx_status_to_napi_status(status); +} + +napi_status napi_open_escapable_handle_scope( + napi_env env, napi_escapable_handle_scope* result) { + NAPI_TRY_ENV(env); + NAPI_WEAK_ASSERT(napi_invalid_arg, result != NULL); + + jerryx_handle_scope_status status; + status = jerryx_open_escapable_handle_scope( + (jerryx_escapable_handle_scope*)result); + + return jerryx_status_to_napi_status(status); +} + +napi_status napi_close_handle_scope(napi_env env, napi_handle_scope scope) { + NAPI_TRY_ENV(env); + jerryx_handle_scope_status status; + status = jerryx_close_handle_scope((jerryx_handle_scope)scope); + + return jerryx_status_to_napi_status(status); +} + +napi_status napi_close_escapable_handle_scope( + napi_env env, napi_escapable_handle_scope scope) { + NAPI_TRY_ENV(env); + jerryx_handle_scope_status status; + status = + jerryx_close_escapable_handle_scope((jerryx_escapable_handle_scope)scope); + + return jerryx_status_to_napi_status(status); +} + +napi_status napi_escape_handle(napi_env env, napi_escapable_handle_scope scope, + napi_value escapee, napi_value* result) { + NAPI_TRY_ENV(env); + NAPI_WEAK_ASSERT(napi_invalid_arg, result != NULL); + + jerryx_handle_scope_status status; + status = + jerryx_escape_handle((jerryx_escapable_handle_scope)scope, + AS_JERRY_VALUE(escapee), (jerry_value_t*)result); + + return jerryx_status_to_napi_status(status); +} + +napi_status napi_create_reference(napi_env env, napi_value value, + uint32_t initial_refcount, napi_ref* result) { + NAPI_TRY_ENV(env); + NAPI_WEAK_ASSERT(napi_invalid_arg, result != NULL); + + jerry_value_t jval = AS_JERRY_VALUE(value); + iotjs_object_info_t* info = + iotjs_get_object_native_info(jval, sizeof(iotjs_object_info_t)); + + iotjs_reference_t* ref = IOTJS_ALLOC(iotjs_reference_t); + ref->refcount = initial_refcount; + ref->jval = AS_JERRY_VALUE(value); + ref->next = NULL; + + if (info->ref_start == NULL) { + ref->prev = NULL; + info->ref_start = ref; + info->ref_end = ref; + } else { + ref->prev = info->ref_end; + + info->ref_end->next = ref; + info->ref_end = ref; + } + + for (uint32_t i = 0; i < ref->refcount; ++i) { + jerry_acquire_value(ref->jval); + } + + NAPI_ASSIGN(result, (napi_ref)ref); + NAPI_RETURN(napi_ok); +} + +napi_status napi_delete_reference(napi_env env, napi_ref ref) { + NAPI_TRY_ENV(env); + iotjs_reference_t* iotjs_ref = (iotjs_reference_t*)ref; + if (jerry_value_is_object(iotjs_ref->jval)) { + jerry_value_t jval = iotjs_ref->jval; + iotjs_object_info_t* info = + iotjs_get_object_native_info(jval, sizeof(iotjs_object_info_t)); + + bool found = false; + iotjs_reference_t* comp = info->ref_start; + while (comp != NULL) { + if (comp == iotjs_ref) { + found = true; + break; + } + comp = comp->next; + } + + NAPI_WEAK_ASSERT(napi_invalid_arg, found); + if (info->ref_start == iotjs_ref) { + info->ref_start = iotjs_ref->next; + } + if (info->ref_end == iotjs_ref) { + info->ref_end = iotjs_ref->prev; + } + if (iotjs_ref->prev != NULL) { + iotjs_ref->prev->next = iotjs_ref->next; + } + if (iotjs_ref->next != NULL) { + iotjs_ref->next->prev = iotjs_ref->prev; + } + } + + for (uint32_t i = 0; i < iotjs_ref->refcount; ++i) { + jerry_release_value(iotjs_ref->jval); + } + IOTJS_RELEASE(iotjs_ref); + NAPI_RETURN(napi_ok); +} + +napi_status napi_reference_ref(napi_env env, napi_ref ref, uint32_t* result) { + NAPI_TRY_ENV(env); + iotjs_reference_t* iotjs_ref = (iotjs_reference_t*)ref; + NAPI_WEAK_ASSERT(napi_invalid_arg, jerry_value_is_object(iotjs_ref->jval)); + + jerry_acquire_value(iotjs_ref->jval); + iotjs_ref->refcount += 1; + + NAPI_ASSIGN(result, iotjs_ref->refcount); + NAPI_RETURN(napi_ok); +} + +napi_status napi_reference_unref(napi_env env, napi_ref ref, uint32_t* result) { + NAPI_TRY_ENV(env); + iotjs_reference_t* iotjs_ref = (iotjs_reference_t*)ref; + NAPI_WEAK_ASSERT(napi_invalid_arg, (iotjs_ref->refcount > 0)); + + jerry_release_value(iotjs_ref->jval); + iotjs_ref->refcount -= 1; + + NAPI_ASSIGN(result, iotjs_ref->refcount); + NAPI_RETURN(napi_ok); +} + +napi_status napi_get_reference_value(napi_env env, napi_ref ref, + napi_value* result) { + NAPI_TRY_ENV(env); + iotjs_reference_t* iotjs_ref = (iotjs_reference_t*)ref; + return napi_assign_nvalue(iotjs_ref->jval, result); +} + +napi_status napi_open_callback_scope(napi_env env, napi_value resource_object, + napi_async_context context, + napi_callback_scope* result) { + NAPI_TRY_ENV(env); + return napi_open_handle_scope(env, (napi_handle_scope*)result); +} + +napi_status napi_close_callback_scope(napi_env env, napi_callback_scope scope) { + NAPI_TRY_ENV(env); + return napi_close_handle_scope(env, (napi_handle_scope)scope); +} + +napi_status napi_add_env_cleanup_hook(napi_env env, void (*fun)(void* arg), + void* arg) { + NAPI_TRY_ENV(env); + iotjs_napi_env_t* curr_env = (iotjs_napi_env_t*)env; + iotjs_cleanup_hook_t* memo = NULL; + iotjs_cleanup_hook_t* hook = curr_env->cleanup_hook; + + while (hook != NULL) { + if (fun == hook->fn) { + NAPI_WEAK_ASSERT(napi_invalid_arg, arg != hook->arg); + } + memo = hook; + hook = hook->next; + } + + iotjs_cleanup_hook_t* new_hook = IOTJS_ALLOC(iotjs_cleanup_hook_t); + new_hook->fn = fun; + new_hook->arg = arg; + new_hook->next = NULL; + + if (memo == NULL) { + curr_env->cleanup_hook = new_hook; + } else { + memo->next = new_hook; + } + + NAPI_RETURN(napi_ok); +} + +napi_status napi_remove_env_cleanup_hook(napi_env env, void (*fun)(void* arg), + void* arg) { + NAPI_TRY_ENV(env); + iotjs_napi_env_t* curr_env = (iotjs_napi_env_t*)env; + iotjs_cleanup_hook_t* memo = NULL; + iotjs_cleanup_hook_t* hook = curr_env->cleanup_hook; + bool found = false; + while (hook != NULL) { + if (fun == hook->fn && arg == hook->arg) { + found = true; + break; + } + memo = hook; + hook = hook->next; + } + + NAPI_WEAK_ASSERT(napi_invalid_arg, found); + if (memo == NULL) { + curr_env->cleanup_hook = hook->next; + } else { + memo->next = hook->next; + } + IOTJS_RELEASE(hook); + NAPI_RETURN(napi_ok); +} + +void iotjs_setup_napi() { + iotjs_napi_env_t* env = (iotjs_napi_env_t*)iotjs_get_current_napi_env(); + env->main_thread = uv_thread_self(); +} + +void iotjs_cleanup_napi() { + iotjs_napi_env_t* env = (iotjs_napi_env_t*)iotjs_get_current_napi_env(); + iotjs_cleanup_hook_t* hook = env->cleanup_hook; + while (hook != NULL) { + hook->fn(hook->arg); + iotjs_cleanup_hook_t* memo = hook; + hook = hook->next; + IOTJS_RELEASE(memo); + } +} diff --git a/src/napi/node_api_module.c b/src/napi/node_api_module.c new file mode 100644 index 0000000000..34944f0f50 --- /dev/null +++ b/src/napi/node_api_module.c @@ -0,0 +1,73 @@ +/* Copyright 2018-present Rokid 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 "jerryscript-ext/handle-scope.h" +#include "internal/node_api_internal.h" + +static napi_module* mod_pending; + +void napi_module_register(napi_module* mod) { + mod_pending = mod; +} + +int napi_module_init_pending(jerry_value_t* exports) { + if (mod_pending == NULL) { + return napi_module_no_pending; + } + + napi_addon_register_func init = + (napi_addon_register_func)mod_pending->nm_register_func; + + if (init == NULL) { + return napi_module_no_nm_register_func; + } + + napi_env env = iotjs_get_current_napi_env(); + + jerryx_handle_scope scope; + jerryx_open_handle_scope(&scope); + + jerry_value_t jval_exports = jerry_create_object(); + napi_value nvalue_ret = (*init)(env, AS_NAPI_VALUE(jval_exports)); + + if (nvalue_ret == NULL) { + *exports = jerry_create_undefined(); + jerry_release_value(jval_exports); + } else { + jerry_value_t jval_ret = AS_JERRY_VALUE(nvalue_ret); + if (jval_ret != jval_exports) { + jerry_release_value(jval_exports); + jerryx_remove_handle(scope, jval_ret, &jval_ret); + } + *exports = jval_ret; + } + + jerryx_close_handle_scope(scope); + + mod_pending = NULL; + + if (iotjs_napi_is_exception_pending(env)) { + jerry_value_t jval_err; + jval_err = iotjs_napi_env_get_and_clear_exception(env); + if (jval_err == (uintptr_t)NULL) { + jval_err = iotjs_napi_env_get_and_clear_fatal_exception(env); + } + jerry_release_value(jval_exports); + *exports = jval_err; + return napi_pending_exception; + } + return napi_module_load_ok; +} diff --git a/src/napi/node_api_object_wrap.c b/src/napi/node_api_object_wrap.c new file mode 100644 index 0000000000..a035b53fe8 --- /dev/null +++ b/src/napi/node_api_object_wrap.c @@ -0,0 +1,99 @@ +/* Copyright 2018-present Rokid 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_def.h" +#include "internal/node_api_internal.h" + +napi_status napi_define_class(napi_env env, const char* utf8name, size_t length, + napi_callback constructor, void* data, + size_t property_count, + const napi_property_descriptor* properties, + napi_value* result) { + NAPI_TRY_ENV(env); + napi_value nval; + NAPI_INTERNAL_CALL( + napi_create_function(env, utf8name, length, constructor, data, &nval)); + + // `prototype` is undefined in `napi_create_function` results + napi_value nval_prototype; + NAPI_INTERNAL_CALL(napi_create_object(env, &nval_prototype)); + NAPI_INTERNAL_CALL( + napi_set_named_property(env, nval, "prototype", nval_prototype)); + + for (size_t i = 0; i < property_count; ++i) { + napi_property_descriptor prop = properties[i]; + if (prop.attributes & napi_static) { + NAPI_INTERNAL_CALL(napi_define_properties(env, nval, 1, &prop)); + } else { + NAPI_INTERNAL_CALL(napi_define_properties(env, nval_prototype, 1, &prop)); + } + } + + NAPI_ASSIGN(result, nval); + NAPI_RETURN(napi_ok); +} + +napi_status napi_wrap(napi_env env, napi_value js_object, void* native_object, + napi_finalize finalize_cb, void* finalize_hint, + napi_ref* result) { + NAPI_TRY_ENV(env); + jerry_value_t jval = AS_JERRY_VALUE(js_object); + NAPI_TRY_TYPE(object, jval); + + iotjs_object_info_t* object_info = + iotjs_get_object_native_info(jval, sizeof(iotjs_object_info_t)); + + NAPI_WEAK_ASSERT(napi_invalid_arg, (object_info->native_object == NULL)); + NAPI_WEAK_ASSERT(napi_invalid_arg, (object_info->finalize_cb == NULL)); + NAPI_WEAK_ASSERT(napi_invalid_arg, (object_info->finalize_hint == NULL)); + + object_info->env = env; + object_info->native_object = native_object; + object_info->finalize_cb = finalize_cb; + object_info->finalize_hint = finalize_hint; + + if (result != NULL) { + return napi_create_reference(env, js_object, 0, result); + } + NAPI_RETURN(napi_ok); +} + +napi_status napi_unwrap(napi_env env, napi_value js_object, void** result) { + NAPI_TRY_ENV(env); + jerry_value_t jval = AS_JERRY_VALUE(js_object); + NAPI_TRY_TYPE(object, jval); + + iotjs_object_info_t* object_info = + iotjs_get_object_native_info(jval, sizeof(iotjs_object_info_t)); + + NAPI_ASSIGN(result, object_info->native_object); + NAPI_RETURN(napi_ok); +} + +napi_status napi_remove_wrap(napi_env env, napi_value js_object, + void** result) { + NAPI_TRY_ENV(env); + jerry_value_t jval = AS_JERRY_VALUE(js_object); + iotjs_object_info_t* object_info = + iotjs_get_object_native_info(jval, sizeof(iotjs_object_info_t)); + + NAPI_ASSIGN(result, object_info->native_object); + + object_info->native_object = NULL; + object_info->finalize_cb = NULL; + object_info->finalize_hint = NULL; + + NAPI_RETURN(napi_ok); +} diff --git a/src/napi/node_api_property.c b/src/napi/node_api_property.c new file mode 100644 index 0000000000..6e3575eefc --- /dev/null +++ b/src/napi/node_api_property.c @@ -0,0 +1,334 @@ +/* Copyright 2019-present Samsung Electronics Co., Ltd. and other contributors + * Copyright 2018-present Rokid 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 "jerryscript-ext/handle-scope.h" +#include "jerryscript.h" +#include "internal/node_api_internal.h" + +#include + +napi_status napi_get_property_names(napi_env env, napi_value object, + napi_value* result) { + NAPI_TRY_ENV(env); + jerry_value_t jval = AS_JERRY_VALUE(object); + NAPI_TRY_TYPE(object, jval); + + jerry_value_t jval_keys = jerry_get_object_keys(jval); + jerryx_create_handle(jval_keys); + if (jerry_value_is_error(jval_keys)) { + jerry_release_value(jval_keys); + NAPI_RETURN(napi_invalid_arg); + } + + return napi_assign_nvalue(jval_keys, result); +} + +napi_status napi_set_property(napi_env env, napi_value object, napi_value key, + napi_value value) { + NAPI_TRY_ENV(env); + jerry_value_t jval_object = AS_JERRY_VALUE(object); + jerry_value_t jval_key = AS_JERRY_VALUE(key); + jerry_value_t jval_val = AS_JERRY_VALUE(value); + + NAPI_TRY_TYPE(object, jval_object); + NAPI_TRY_TYPE(string, jval_key); + + jerry_value_t ret = jerry_set_property(jval_object, jval_key, jval_val); + if (jerry_value_is_error(ret)) { + jerry_release_value(ret); + NAPI_RETURN(napi_invalid_arg); + } + + jerry_release_value(ret); + NAPI_RETURN(napi_ok); +} + +napi_status napi_get_property(napi_env env, napi_value object, napi_value key, + napi_value* result) { + NAPI_TRY_ENV(env); + jerry_value_t jval_object = AS_JERRY_VALUE(object); + jerry_value_t jval_key = AS_JERRY_VALUE(key); + + NAPI_TRY_TYPE(object, jval_object); + NAPI_TRY_TYPE(string, jval_key); + + jerry_value_t jval_ret = jerry_get_property(jval_object, jval_key); + jerryx_create_handle(jval_ret); + if (jerry_value_is_error(jval_ret)) { + jerry_release_value(jval_ret); + NAPI_RETURN(napi_invalid_arg); + } + + return napi_assign_nvalue(jval_ret, result); +} + +napi_status napi_has_property(napi_env env, napi_value object, napi_value key, + bool* result) { + NAPI_TRY_ENV(env); + jerry_value_t jval_object = AS_JERRY_VALUE(object); + jerry_value_t jval_key = AS_JERRY_VALUE(key); + + NAPI_TRY_TYPE(object, jval_object); + NAPI_TRY_TYPE(string, jval_key); + jerry_value_t has_prop = jerry_has_property(jval_object, jval_key); + NAPI_TRY_TYPE(boolean, has_prop); + + return napi_assign_bool(jerry_get_boolean_value(has_prop), result); +} + +napi_status napi_delete_property(napi_env env, napi_value object, + napi_value key, bool* result) { + NAPI_TRY_ENV(env); + jerry_value_t jval_object = AS_JERRY_VALUE(object); + jerry_value_t jval_key = AS_JERRY_VALUE(key); + + NAPI_TRY_TYPE(object, jval_object); + NAPI_TRY_TYPE(string, jval_key); + + return napi_assign_bool(jerry_delete_property(jval_object, jval_key), result); +} + +napi_status napi_has_own_property(napi_env env, napi_value object, + napi_value key, bool* result) { + NAPI_TRY_ENV(env); + jerry_value_t jval_object = AS_JERRY_VALUE(object); + jerry_value_t jval_key = AS_JERRY_VALUE(key); + + NAPI_TRY_TYPE(object, jval_object); + NAPI_TRY_TYPE(string, jval_key); + jerry_value_t has_prop = jerry_has_own_property(jval_object, jval_key); + NAPI_TRY_TYPE(boolean, has_prop); + + return napi_assign_bool(jerry_get_boolean_value(has_prop), result); +} + +napi_status napi_set_named_property(napi_env env, napi_value object, + const char* utf8Name, napi_value value) { + NAPI_TRY_ENV(env); + jerry_value_t jval_object = AS_JERRY_VALUE(object); + NAPI_TRY_TYPE(object, jval_object); + + jerry_value_t jval_key = + jerry_create_string_from_utf8((jerry_char_t*)utf8Name); + napi_status status = + napi_set_property(env, object, AS_NAPI_VALUE(jval_key), value); + jerry_release_value(jval_key); + return status; +} + +napi_status napi_get_named_property(napi_env env, napi_value object, + const char* utf8Name, napi_value* result) { + NAPI_TRY_ENV(env); + jerry_value_t jval_object = AS_JERRY_VALUE(object); + NAPI_TRY_TYPE(object, jval_object); + + jerry_value_t jval_key = + jerry_create_string_from_utf8((jerry_char_t*)utf8Name); + napi_status status = + napi_get_property(env, object, AS_NAPI_VALUE(jval_key), result); + jerry_release_value(jval_key); + return status; +} + +napi_status napi_has_named_property(napi_env env, napi_value object, + const char* utf8Name, bool* result) { + NAPI_TRY_ENV(env); + jerry_value_t jval_object = AS_JERRY_VALUE(object); + NAPI_TRY_TYPE(object, jval_object); + + jerry_value_t jval_key = + jerry_create_string_from_utf8((jerry_char_t*)utf8Name); + napi_status status = + napi_has_property(env, object, AS_NAPI_VALUE(jval_key), result); + jerry_release_value(jval_key); + return status; +} + +napi_status napi_set_element(napi_env env, napi_value object, uint32_t index, + napi_value value) { + NAPI_TRY_ENV(env); + jerry_value_t jval_object = AS_JERRY_VALUE(object); + jerry_value_t jval_val = AS_JERRY_VALUE(value); + + NAPI_TRY_TYPE(object, jval_object); + + jerry_value_t res = jerry_set_property_by_index(jval_object, index, jval_val); + if (jerry_value_is_error(res)) { + jerry_release_value(res); + NAPI_RETURN(napi_invalid_arg); + } + + jerry_release_value(res); + NAPI_RETURN(napi_ok); +} + +napi_status napi_get_element(napi_env env, napi_value object, uint32_t index, + napi_value* result) { + NAPI_TRY_ENV(env); + jerry_value_t jval_object = AS_JERRY_VALUE(object); + + NAPI_TRY_TYPE(object, jval_object); + + jerry_value_t jval_ret = jerry_get_property_by_index(jval_object, index); + jerryx_create_handle(jval_ret); + if (jerry_value_is_error(jval_ret)) { + jerry_release_value(jval_ret); + NAPI_RETURN(napi_invalid_arg); + } + return napi_assign_nvalue(jval_ret, result); +} + +napi_status napi_has_element(napi_env env, napi_value object, uint32_t index, + bool* result) { + NAPI_TRY_ENV(env); + jerry_value_t jval_object = AS_JERRY_VALUE(object); + NAPI_TRY_TYPE(object, jval_object); + + char idx_str[17]; + sprintf(idx_str, "%d", index); + jerry_value_t prop_name = jerry_create_string((const jerry_char_t*)idx_str); + jerry_value_t has_prop_val = jerry_has_own_property(jval_object, prop_name); + jerry_release_value(prop_name); + + if (jerry_value_is_error(has_prop_val)) { + jerry_release_value(has_prop_val); + NAPI_RETURN(napi_generic_failure); + } + + bool has_prop = jerry_get_boolean_value(has_prop_val); + return napi_assign_bool(has_prop, result); +} + +napi_status napi_delete_element(napi_env env, napi_value object, uint32_t index, + bool* result) { + NAPI_TRY_ENV(env); + jerry_value_t jval_object = AS_JERRY_VALUE(object); + NAPI_TRY_TYPE(object, jval_object); + + return napi_assign_bool(jerry_delete_property_by_index(jval_object, index), + result); +} + +napi_status iotjs_napi_prop_desc_to_jdesc(napi_env env, + const napi_property_descriptor* ndesc, + jerry_property_descriptor_t* jdesc) { + napi_status status; + + if (ndesc->attributes & napi_configurable) { + jdesc->is_configurable_defined = true; + jdesc->is_configurable = true; + } + + if (ndesc->attributes & napi_enumerable) { + jdesc->is_enumerable_defined = true; + jdesc->is_enumerable = true; + } + + if (ndesc->attributes & napi_writable) { + jdesc->is_writable_defined = true; + jdesc->is_writable = true; + } + + if (ndesc->value != NULL) { + jdesc->is_value_defined = true; + jdesc->value = AS_JERRY_VALUE(ndesc->value); + NAPI_RETURN(napi_ok); + } + + if (ndesc->method != NULL) { + napi_value method; + status = napi_create_function(env, "method", 6, ndesc->method, ndesc->data, + &method); + if (status != napi_ok) + return status; + jdesc->is_value_defined = true; + jdesc->value = AS_JERRY_VALUE(method); + NAPI_RETURN(napi_ok); + } + + if (ndesc->getter != NULL) { + napi_value getter; + status = napi_create_function(env, "getter", 6, ndesc->getter, ndesc->data, + &getter); + if (status != napi_ok) + return status; + jdesc->is_get_defined = true; + jdesc->getter = AS_JERRY_VALUE(getter); + /** jerryscript asserts xor is_writable_defined and accessors */ + jdesc->is_writable_defined = false; + } + + if (ndesc->setter != NULL) { + napi_value setter; + status = napi_create_function(env, "setter", 6, ndesc->setter, ndesc->data, + &setter); + if (status != napi_ok) + return status; + jdesc->is_set_defined = true; + jdesc->setter = AS_JERRY_VALUE(setter); + /** jerryscript asserts xor is_writable_defined and accessors */ + jdesc->is_writable_defined = false; + } + + NAPI_RETURN(napi_ok); +} + +napi_status napi_define_properties(napi_env env, napi_value object, + size_t property_count, + const napi_property_descriptor* properties) { + NAPI_TRY_ENV(env); + jerry_value_t jval_target = AS_JERRY_VALUE(object); + NAPI_TRY_TYPE(object, jval_target); + NAPI_WEAK_ASSERT(napi_invalid_arg, properties != NULL); + + napi_status status; + jerry_property_descriptor_t prop_desc; + for (size_t i = 0; i < property_count; ++i) { + jerry_init_property_descriptor_fields(&prop_desc); + napi_property_descriptor prop = properties[i]; + + jerry_value_t jval_prop_name; + if (prop.utf8name != NULL) { + jval_prop_name = + jerry_create_string_from_utf8((jerry_char_t*)prop.utf8name); + jerryx_create_handle(jval_prop_name); + } else if (prop.name != NULL) { + jval_prop_name = AS_JERRY_VALUE(prop.name); + NAPI_TRY_TYPE(string, jval_prop_name); + } else { + NAPI_RETURN(napi_invalid_arg); + } + + status = iotjs_napi_prop_desc_to_jdesc(env, &prop, &prop_desc); + if (status != napi_ok) + return status; + + jerry_value_t return_value = + jerry_define_own_property(jval_target, jval_prop_name, &prop_desc); + if (jerry_value_is_error(return_value)) { + NAPI_RETURN(napi_invalid_arg); + } + jerry_release_value(return_value); + + /** + * We don't have to call `jerry_free_property_descriptor_fields` + * since most napi values are managed by handle scopes. + */ + // jerry_free_property_descriptor_fields(&prop_desc); + } + + NAPI_RETURN(napi_ok); +} diff --git a/src/napi/node_api_value.c b/src/napi/node_api_value.c new file mode 100644 index 0000000000..1bb97e3883 --- /dev/null +++ b/src/napi/node_api_value.c @@ -0,0 +1,848 @@ +/* Copyright 2019-present Samsung Electronics Co., Ltd. and other contributors + * Copyright 2018-present Rokid 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 "jerryscript-ext/handle-scope.h" +#include "jerryscript.h" +#include +#include "internal/node_api_internal.h" +#include "modules/iotjs_module_buffer.h" + +#include + +/* Feature missing error messages */ +const char* const napi_err_no_dataview = + "DataView is not supported by this build."; +const char* const napi_err_no_promise = + "Promise is not supported by this build."; +const char* const napi_err_no_symbol = + "Symbols are not supported by this build."; +const char* const napi_err_no_typedarray = + "TypedArray is not supported by this build."; +const char* const napi_err_invalid_deferred = + "Invalid deferred object. Please refer to the documentation."; + +static void iotjs_napi_buffer_external_free_cb(void* native_p) { + iotjs_buffer_external_info_t* info = (iotjs_buffer_external_info_t*)native_p; + + napi_env env = info->env; + void* external_data = info->external_data; + void* finalize_hint = info->finalize_hint; + napi_finalize finalize_cb = info->finalize_cb; + if (finalize_cb != NULL) { + finalize_cb(env, external_data, finalize_hint); + } + + IOTJS_RELEASE(info); +} + +napi_status napi_assign_bool(bool value, bool* result) { + NAPI_ASSIGN(result, value); + NAPI_RETURN(napi_ok); +} + +napi_status napi_assign_nvalue(jerry_value_t jvalue, napi_value* nvalue) { + NAPI_ASSIGN(nvalue, AS_NAPI_VALUE(jvalue)); + NAPI_RETURN(napi_ok); +} + +napi_status napi_create_array(napi_env env, napi_value* result) { + NAPI_TRY_ENV(env); + JERRYX_CREATE(jval, jerry_create_array(0)); + return napi_assign_nvalue(jval, result); +} + +napi_status napi_create_array_with_length(napi_env env, size_t length, + napi_value* result) { + NAPI_TRY_ENV(env); + JERRYX_CREATE(jval, jerry_create_array(length)); + return napi_assign_nvalue(jval, result); +} + +napi_status napi_create_arraybuffer(napi_env env, size_t byte_length, + void** data, napi_value* result) { + NAPI_TRY_ENV(env); + + if (!jerry_is_feature_enabled(JERRY_FEATURE_TYPEDARRAY)) { + NAPI_ASSIGN(data, NULL); + NAPI_ASSIGN(result, NULL); + NAPI_RETURN_WITH_MSG(napi_generic_failure, napi_err_no_typedarray); + } + + JERRYX_CREATE(jval, jerry_create_arraybuffer(byte_length)); + uint8_t* data_ptr = jerry_get_arraybuffer_pointer(jval); + NAPI_ASSIGN(data, data_ptr); + NAPI_ASSIGN(result, AS_NAPI_VALUE(jval)); + NAPI_RETURN(napi_ok); +} + +static void iotjs_napi_arraybuffer_external_free_cb(void* native_p) { + IOTJS_UNUSED(native_p); +} + +napi_status napi_create_external_arraybuffer(napi_env env, void* external_data, + size_t byte_length, + napi_finalize finalize_cb, + void* finalize_hint, + napi_value* result) { + NAPI_TRY_ENV(env); + NAPI_WEAK_ASSERT_WITH_MSG(napi_invalid_arg, external_data != NULL, + "External data pointer could not be NULL."); + NAPI_WEAK_ASSERT_WITH_MSG(napi_invalid_arg, byte_length != 0, + "External data byte length could not be 0."); + + if (!jerry_is_feature_enabled(JERRY_FEATURE_TYPEDARRAY)) { + NAPI_ASSIGN(result, NULL); + NAPI_RETURN_WITH_MSG(napi_generic_failure, napi_err_no_typedarray); + } + + JERRYX_CREATE(jval_arrbuf, jerry_create_arraybuffer_external( + byte_length, external_data, + iotjs_napi_arraybuffer_external_free_cb)); + + iotjs_object_info_t* info = + iotjs_get_object_native_info(jval_arrbuf, sizeof(iotjs_object_info_t)); + info->env = env; + info->native_object = external_data; + info->finalize_hint = finalize_hint; + info->finalize_cb = finalize_cb; + + NAPI_ASSIGN(result, AS_NAPI_VALUE(jval_arrbuf)); + NAPI_RETURN(napi_ok); +} + +napi_status napi_create_typedarray(napi_env env, napi_typedarray_type type, + size_t length, napi_value arraybuffer, + size_t byte_offset, napi_value* result) { + NAPI_TRY_ENV(env); + + if (!jerry_is_feature_enabled(JERRY_FEATURE_TYPEDARRAY)) { + NAPI_ASSIGN(result, NULL); + NAPI_RETURN_WITH_MSG(napi_generic_failure, napi_err_no_typedarray); + } + + jerry_typedarray_type_t jtype; +#define CASE_NAPI_TYPEDARRAY_TYPE(type_name, jtype_name) \ + case napi_##type_name##_array: \ + jtype = JERRY_TYPEDARRAY_##jtype_name; \ + break; + + switch (type) { + CASE_NAPI_TYPEDARRAY_TYPE(int8, INT8); + CASE_NAPI_TYPEDARRAY_TYPE(uint8, UINT8); + CASE_NAPI_TYPEDARRAY_TYPE(uint8_clamped, UINT8CLAMPED); + CASE_NAPI_TYPEDARRAY_TYPE(int16, INT16); + CASE_NAPI_TYPEDARRAY_TYPE(uint16, UINT16); + CASE_NAPI_TYPEDARRAY_TYPE(int32, INT32); + CASE_NAPI_TYPEDARRAY_TYPE(uint32, UINT32); + CASE_NAPI_TYPEDARRAY_TYPE(float32, FLOAT32); + CASE_NAPI_TYPEDARRAY_TYPE(float64, FLOAT64); + default: + jtype = JERRY_TYPEDARRAY_INVALID; + } +#undef CASE_NAPI_TYPEDARRAY_TYPE + + jerry_value_t jval_arraybuffer = AS_JERRY_VALUE(arraybuffer); + JERRYX_CREATE(jval, + jerry_create_typedarray_for_arraybuffer_sz(jtype, + jval_arraybuffer, + byte_offset, + length)); + NAPI_ASSIGN(result, AS_NAPI_VALUE(jval)); + NAPI_RETURN(napi_ok); +} + +napi_status napi_create_buffer(napi_env env, size_t size, void** data, + napi_value* result) { + NAPI_TRY_ENV(env); + JERRYX_CREATE(jval_buf, iotjs_bufferwrap_create_buffer(size)); + iotjs_bufferwrap_t* buf_wrap = iotjs_bufferwrap_from_jbuffer(jval_buf); + + NAPI_ASSIGN(data, buf_wrap->buffer); + + return napi_assign_nvalue(jval_buf, result); +} + +napi_status napi_create_buffer_copy(napi_env env, size_t size, const void* data, + void** result_data, napi_value* result) { + NAPI_TRY_ENV(env); + JERRYX_CREATE(jval_buf, iotjs_bufferwrap_create_buffer(size)); + iotjs_bufferwrap_t* buf_wrap = iotjs_bufferwrap_from_jbuffer(jval_buf); + + iotjs_bufferwrap_copy(buf_wrap, (char*)data, size); + + NAPI_ASSIGN(result_data, buf_wrap->buffer); + + return napi_assign_nvalue(jval_buf, result); +} + +napi_status napi_create_dataview(napi_env env, size_t byte_length, + napi_value arraybuffer, size_t byte_offset, + napi_value* result) { + NAPI_TRY_ENV(env); + + if (!jerry_is_feature_enabled(JERRY_FEATURE_DATAVIEW)) { + NAPI_ASSIGN(result, NULL); + NAPI_RETURN_WITH_MSG(napi_generic_failure, napi_err_no_dataview); + } + + NAPI_WEAK_ASSERT_WITH_MSG(napi_invalid_arg, byte_length != 0, + "External data byte length could not be 0."); + jerry_value_t jval_arraybuffer = AS_JERRY_VALUE(arraybuffer); + + NAPI_WEAK_ASSERT_WITH_MSG(napi_invalid_arg, + jerry_value_is_arraybuffer(jval_arraybuffer), + "Argument must be a valid ArrayBuffer object."); + + JERRYX_CREATE(jval_dv, jerry_create_dataview(jval_arraybuffer, byte_offset, + byte_length)); + NAPI_ASSIGN(result, AS_NAPI_VALUE(jval_dv)); + NAPI_RETURN(napi_ok); +} + +static void napi_external_destroy(iotjs_object_info_t* info) { + if (info->finalize_cb != NULL) { + info->finalize_cb(info->env, info->native_object, info->finalize_hint); + } + + IOTJS_RELEASE(info); +} + +static const jerry_object_native_info_t napi_external_native_info = { + .free_cb = (jerry_object_native_free_callback_t)napi_external_destroy +}; + +napi_status napi_create_external(napi_env env, void* data, + napi_finalize finalize_cb, void* finalize_hint, + napi_value* result) { + NAPI_TRY_ENV(env); + napi_value nval; + NAPI_INTERNAL_CALL(napi_create_object(env, &nval)); + iotjs_object_info_t* info = + (iotjs_object_info_t*)iotjs_buffer_allocate(sizeof(iotjs_object_info_t)); + info->native_object = data; + info->finalize_cb = finalize_cb; + info->finalize_hint = finalize_hint; + + jerry_set_object_native_pointer(AS_JERRY_VALUE(nval), info, + &napi_external_native_info); + + NAPI_ASSIGN(result, nval); + NAPI_RETURN(napi_ok); +} + +napi_status napi_create_external_buffer(napi_env env, size_t length, void* data, + napi_finalize finalize_cb, + void* finalize_hint, + napi_value* result) { + NAPI_TRY_ENV(env); + char* nval = NULL; + napi_value res; + NAPI_INTERNAL_CALL( + napi_create_buffer_copy(env, length, data, (void**)&nval, &res)); + + jerry_value_t jbuffer = AS_JERRY_VALUE(res); + iotjs_bufferwrap_t* bufferwrap = iotjs_bufferwrap_from_jbuffer(jbuffer); + iotjs_buffer_external_info_t* info = + IOTJS_ALLOC(iotjs_buffer_external_info_t); + + info->env = env; + info->external_data = data; + info->finalize_hint = finalize_hint; + info->finalize_cb = finalize_cb; + + iotjs_bufferwrap_set_external_callback(bufferwrap, + iotjs_napi_buffer_external_free_cb, + info); + + NAPI_ASSIGN(result, res); + NAPI_RETURN(napi_ok); +} + +napi_status napi_create_object(napi_env env, napi_value* result) { + NAPI_TRY_ENV(env); + JERRYX_CREATE(jval, jerry_create_object()); + return napi_assign_nvalue(jval, result); +} + +static napi_status napi_create_error_helper(jerry_error_t jerry_error_type, + napi_env env, napi_value code, + napi_value msg, + napi_value* result) { + NAPI_TRY_ENV(env); + + jerry_value_t jval_code = AS_JERRY_VALUE(code); + jerry_value_t jval_msg = AS_JERRY_VALUE(msg); + + NAPI_TRY_TYPE(string, jval_msg); + + jerry_size_t msg_size = jerry_get_utf8_string_size(jval_msg); + jerry_char_t* raw_msg = IOTJS_CALLOC(msg_size + 1, jerry_char_t); + jerry_size_t written_size = + jerry_string_to_utf8_char_buffer(jval_msg, raw_msg, msg_size); + NAPI_WEAK_ASSERT(napi_invalid_arg, written_size == msg_size); + raw_msg[msg_size] = '\0'; + + jerry_value_t jval_error = jerry_create_error(jerry_error_type, raw_msg); + + IOTJS_RELEASE(raw_msg); + + /** code has to be an JS string type, thus it can not be an number 0 */ + if (code != NULL) { + NAPI_TRY_TYPE(string, jval_code); + jval_error = jerry_get_value_from_error(jval_error, true); + iotjs_jval_set_property_jval(jval_error, IOTJS_MAGIC_STRING_CODE, + jval_code); + } + + jerryx_create_handle(jval_error); + NAPI_ASSIGN(result, AS_NAPI_VALUE(jval_error)); + + NAPI_RETURN(napi_ok); +} + +napi_status napi_create_error(napi_env env, napi_value code, napi_value msg, + napi_value* result) { + return napi_create_error_helper(JERRY_ERROR_COMMON, env, code, msg, result); +} + +napi_status napi_create_range_error(napi_env env, napi_value code, + napi_value msg, napi_value* result) { + return napi_create_error_helper(JERRY_ERROR_RANGE, env, code, msg, result); +} + +napi_status napi_create_type_error(napi_env env, napi_value code, + napi_value msg, napi_value* result) { + return napi_create_error_helper(JERRY_ERROR_TYPE, env, code, msg, result); +} + +static napi_status napi_number_convert_from_c_type_helper(napi_env env, + double value, + napi_value* result) { + NAPI_TRY_ENV(env); + JERRYX_CREATE(jval, jerry_create_number(value)); + return napi_assign_nvalue(jval, result); +} + +#define DEF_NAPI_NUMBER_CONVERT_FROM_C_TYPE(type, name) \ + napi_status napi_create_##name(napi_env env, type value, \ + napi_value* result) { \ + return napi_number_convert_from_c_type_helper(env, (double)value, result); \ + } + +DEF_NAPI_NUMBER_CONVERT_FROM_C_TYPE(int32_t, int32); +DEF_NAPI_NUMBER_CONVERT_FROM_C_TYPE(uint32_t, uint32); +DEF_NAPI_NUMBER_CONVERT_FROM_C_TYPE(int64_t, int64); +DEF_NAPI_NUMBER_CONVERT_FROM_C_TYPE(double, double); +#undef DEF_NAPI_NUMBER_CONVERT_FROM_C_TYPE + +napi_status napi_get_value_double(napi_env env, napi_value value, + double* result) { + NAPI_TRY_ENV(env); + jerry_value_t jval = AS_JERRY_VALUE(value); + NAPI_TRY_TYPE(number, jval); + NAPI_ASSIGN(result, jerry_get_number_value(jval)); + NAPI_RETURN(napi_ok); +} + +#define DEF_NAPI_NUMBER_CONVERT_FROM_NVALUE(type, name) \ + napi_status napi_get_value_##name(napi_env env, napi_value value, \ + type* result) { \ + NAPI_TRY_ENV(env); \ + jerry_value_t jval = AS_JERRY_VALUE(value); \ + NAPI_TRY_TYPE(number, jval); \ + double num = jerry_get_number_value(jval); \ + if (isinf(num) || isnan(num)) { \ + num = 0; \ + } \ + NAPI_ASSIGN(result, num); \ + NAPI_RETURN(napi_ok); \ + } + +DEF_NAPI_NUMBER_CONVERT_FROM_NVALUE(int32_t, int32); +DEF_NAPI_NUMBER_CONVERT_FROM_NVALUE(int64_t, int64); +DEF_NAPI_NUMBER_CONVERT_FROM_NVALUE(uint32_t, uint32); +#undef DEF_NAPI_NUMBER_CONVERT_FROM_NVALUE + +napi_status napi_create_symbol(napi_env env, napi_value description, + napi_value* result) { + NAPI_TRY_ENV(env); + + if (!jerry_is_feature_enabled(JERRY_FEATURE_SYMBOL)) { + NAPI_ASSIGN(result, NULL); + NAPI_RETURN_WITH_MSG(napi_generic_failure, napi_err_no_symbol); + } + + JERRYX_CREATE(jval, jerry_create_symbol(AS_JERRY_VALUE(description))); + NAPI_ASSIGN(result, AS_NAPI_VALUE(jval)); + NAPI_RETURN(napi_ok); +} + +napi_status napi_create_string_utf8(napi_env env, const char* str, + size_t length, napi_value* result) { + NAPI_TRY_ENV(env); + if (length == NAPI_AUTO_LENGTH) { + length = strlen(str); + } + JERRYX_CREATE(jval, + jerry_create_string_sz_from_utf8((jerry_char_t*)str, length)); + return napi_assign_nvalue(jval, result); +} + +napi_status napi_get_array_length(napi_env env, napi_value value, + uint32_t* result) { + NAPI_TRY_ENV(env); + jerry_value_t jval = AS_JERRY_VALUE(value); + NAPI_ASSIGN(result, jerry_get_array_length(jval)); + NAPI_RETURN(napi_ok); +} + +napi_status napi_get_arraybuffer_info(napi_env env, napi_value arraybuffer, + void** data, size_t* byte_length) { + NAPI_TRY_ENV(env); + + if (!jerry_is_feature_enabled(JERRY_FEATURE_TYPEDARRAY)) { + NAPI_ASSIGN(byte_length, 0); + NAPI_ASSIGN(data, NULL); + NAPI_RETURN_WITH_MSG(napi_generic_failure, napi_err_no_typedarray); + } + + jerry_value_t jval = AS_JERRY_VALUE(arraybuffer); + jerry_length_t len = jerry_get_arraybuffer_byte_length(jval); + + /** + * WARNING: if the arraybuffer is managed by js engine, + * write beyond address limit may lead to an unpredictable result. + */ + uint8_t* ptr = jerry_get_arraybuffer_pointer(jval); + + NAPI_ASSIGN(byte_length, len); + NAPI_ASSIGN(data, ptr); + NAPI_RETURN(napi_ok); +} + +napi_status napi_get_buffer_info(napi_env env, napi_value value, void** data, + size_t* length) { + NAPI_TRY_ENV(env); + jerry_value_t jval = AS_JERRY_VALUE(value); + iotjs_bufferwrap_t* buf_wrap = iotjs_bufferwrap_from_jbuffer(jval); + NAPI_ASSIGN(data, buf_wrap->buffer); + NAPI_ASSIGN(length, iotjs_bufferwrap_length(buf_wrap)); + + NAPI_RETURN(napi_ok); +} + +napi_status napi_get_prototype(napi_env env, napi_value object, + napi_value* result) { + NAPI_TRY_ENV(env); + jerry_value_t jval = AS_JERRY_VALUE(object); + JERRYX_CREATE(jval_proto, jerry_get_prototype(jval)); + return napi_assign_nvalue(jval_proto, result); +} + +napi_status napi_get_value_bool(napi_env env, napi_value value, bool* result) { + NAPI_TRY_ENV(env); + jerry_value_t jval = AS_JERRY_VALUE(value); + NAPI_TRY_TYPE(boolean, jval); + return napi_assign_bool(jerry_get_boolean_value(jval), result); +} + +napi_status napi_get_boolean(napi_env env, bool value, napi_value* result) { + NAPI_TRY_ENV(env); + JERRYX_CREATE(jval, jerry_create_boolean(value)); + return napi_assign_nvalue(jval, result); +} + +napi_status napi_get_dataview_info(napi_env env, napi_value dataview, + size_t* byte_length, void** data, + napi_value* arraybuffer, + size_t* byte_offset) { + NAPI_TRY_ENV(env); + + if (!jerry_is_feature_enabled(JERRY_FEATURE_DATAVIEW)) { + NAPI_ASSIGN(byte_length, 0); + NAPI_ASSIGN(data, NULL); + NAPI_ASSIGN(arraybuffer, AS_NAPI_VALUE(jerry_create_undefined())); + NAPI_ASSIGN(byte_offset, 0); + NAPI_RETURN_WITH_MSG(napi_generic_failure, napi_err_no_dataview); + } + + jerry_value_t jval = AS_JERRY_VALUE(dataview); + NAPI_WEAK_ASSERT_WITH_MSG(napi_invalid_arg, jerry_value_is_dataview(jval), + "Argument must be a valid DataView object."); + + JERRYX_CREATE(jval_arraybuffer, + jerry_get_dataview_buffer(jval, (jerry_length_t*)byte_offset, + (jerry_length_t*)byte_length)); + uint8_t* ptr = jerry_get_arraybuffer_pointer(jval_arraybuffer); + + NAPI_ASSIGN(arraybuffer, AS_NAPI_VALUE(jval_arraybuffer)); + NAPI_ASSIGN(data, ptr); + NAPI_RETURN(napi_ok); +} + +napi_status napi_get_typedarray_info(napi_env env, napi_value typedarray, + napi_typedarray_type* type, size_t* length, + void** data, napi_value* arraybuffer, + size_t* byte_offset) { + NAPI_TRY_ENV(env); + + if (!jerry_is_feature_enabled(JERRY_FEATURE_TYPEDARRAY)) { + NAPI_ASSIGN(type, napi_int8_array); + NAPI_ASSIGN(length, 0); + NAPI_ASSIGN(data, NULL); + NAPI_ASSIGN(arraybuffer, AS_NAPI_VALUE(jerry_create_undefined())); + NAPI_ASSIGN(byte_offset, 0); + NAPI_RETURN_WITH_MSG(napi_generic_failure, napi_err_no_typedarray); + } + + jerry_value_t jval = AS_JERRY_VALUE(typedarray); + jerry_typedarray_type_t jtype = jerry_get_typedarray_type(jval); + + napi_typedarray_type ntype; +#define CASE_JERRY_TYPEDARRAY_TYPE(jtype_name, type_name) \ + case JERRY_TYPEDARRAY_##jtype_name: { \ + ntype = napi_##type_name##_array; \ + break; \ + } + + switch (jtype) { + CASE_JERRY_TYPEDARRAY_TYPE(INT8, int8); + CASE_JERRY_TYPEDARRAY_TYPE(UINT8, uint8); + CASE_JERRY_TYPEDARRAY_TYPE(UINT8CLAMPED, uint8_clamped); + CASE_JERRY_TYPEDARRAY_TYPE(INT16, int16); + CASE_JERRY_TYPEDARRAY_TYPE(UINT16, uint16); + CASE_JERRY_TYPEDARRAY_TYPE(INT32, int32); + CASE_JERRY_TYPEDARRAY_TYPE(UINT32, uint32); + CASE_JERRY_TYPEDARRAY_TYPE(FLOAT32, float32); + default: { + IOTJS_ASSERT(jtype == JERRY_TYPEDARRAY_FLOAT64); + ntype = napi_float64_array; + break; + } + } +#undef CASE_JERRY_TYPEDARRAY_TYPE + + jerry_length_t jlength = jerry_get_typedarray_length(jval); + jerry_length_t jbyte_offset; + jerry_length_t jbyte_length; + JERRYX_CREATE(jval_arraybuffer, + jerry_get_typedarray_buffer(jval, &jbyte_offset, + &jbyte_length)); + + /** + * WARNING: if the arraybuffer is managed by js engine, + * write beyond address limit may lead to an unpredictable result. + */ + uint8_t* ptr = jerry_get_arraybuffer_pointer(jval); + + NAPI_ASSIGN(type, ntype); + NAPI_ASSIGN(length, jlength); + NAPI_ASSIGN(data, ptr); + NAPI_ASSIGN(arraybuffer, AS_NAPI_VALUE(jval_arraybuffer)); + NAPI_ASSIGN(byte_offset, jbyte_offset); + NAPI_RETURN(napi_ok); +} + +napi_status napi_get_value_external(napi_env env, napi_value value, + void** result) { + NAPI_TRY_ENV(env); + jerry_value_t jval = AS_JERRY_VALUE(value); + iotjs_object_info_t* info = NULL; + if (!jerry_get_object_native_pointer(jval, (void**)&info, + &napi_external_native_info)) { + NAPI_ASSIGN(result, NULL); + NAPI_RETURN_WITH_MSG(napi_invalid_arg, + "Argument must be type of 'napi_external'."); + } + + NAPI_ASSIGN(result, info->native_object); + NAPI_RETURN(napi_ok); +} + +napi_status napi_get_value_string_utf8(napi_env env, napi_value value, + char* buf, size_t bufsize, + size_t* result) { + NAPI_TRY_ENV(env); + jerry_value_t jval = AS_JERRY_VALUE(value); + NAPI_TRY_TYPE(string, jval); + + size_t str_size = jerry_get_utf8_string_size(jval); + if (buf == NULL) { + /* null terminator is excluded */ + NAPI_ASSIGN(result, str_size); + NAPI_RETURN(napi_ok); + } + + jerry_size_t written_size = + jerry_string_to_utf8_char_buffer(jval, (jerry_char_t*)buf, bufsize); + NAPI_WEAK_ASSERT_WITH_MSG(napi_generic_failure, + str_size == 0 || (bufsize > 0 && written_size != 0), + "Insufficient buffer not supported yet."); + /* expects one more byte to write null terminator */ + if (bufsize > written_size) { + buf[written_size] = '\0'; + } + NAPI_ASSIGN(result, written_size); + NAPI_RETURN(napi_ok); +} + +napi_status napi_get_global(napi_env env, napi_value* result) { + NAPI_TRY_ENV(env); + JERRYX_CREATE(jval, jerry_get_global_object()); + return napi_assign_nvalue(jval, result); +} + +napi_status napi_get_null(napi_env env, napi_value* result) { + NAPI_TRY_ENV(env); + JERRYX_CREATE(jval, jerry_create_null()); + return napi_assign_nvalue(jval, result); +} + +napi_status napi_get_undefined(napi_env env, napi_value* result) { + NAPI_TRY_ENV(env); + JERRYX_CREATE(jval, jerry_create_undefined()); + return napi_assign_nvalue(jval, result); +} + +napi_status napi_coerce_to_bool(napi_env env, napi_value value, + napi_value* result) { + NAPI_TRY_ENV(env); + jerry_value_t jval = AS_JERRY_VALUE(value); + bool res = jerry_value_to_boolean(jval); + JERRYX_CREATE(jval_result, jerry_create_boolean(res)); + NAPI_ASSIGN(result, AS_NAPI_VALUE(jval_result)); + NAPI_RETURN(napi_ok); +} + +#define DEF_NAPI_COERCE_TO(type, alias) \ + napi_status napi_coerce_to_##type(napi_env env, napi_value value, \ + napi_value* result) { \ + NAPI_TRY_ENV(env); \ + jerry_value_t jval = AS_JERRY_VALUE(value); \ + JERRYX_CREATE(jval_result, jerry_value_to_##alias(jval)); \ + return napi_assign_nvalue(jval_result, result); \ + } + +DEF_NAPI_COERCE_TO(number, number); +DEF_NAPI_COERCE_TO(object, object); +DEF_NAPI_COERCE_TO(string, string); + +napi_status napi_typeof(napi_env env, napi_value value, + napi_valuetype* result) { + NAPI_TRY_ENV(env); + jerry_value_t jval = AS_JERRY_VALUE(value); + jerry_type_t type = jerry_value_get_type(jval); + + switch (type) { + case JERRY_TYPE_UNDEFINED: { + NAPI_ASSIGN(result, napi_undefined); + break; + } + case JERRY_TYPE_NULL: { + NAPI_ASSIGN(result, napi_null); + break; + } + case JERRY_TYPE_BOOLEAN: { + NAPI_ASSIGN(result, napi_boolean); + break; + } + case JERRY_TYPE_NUMBER: { + NAPI_ASSIGN(result, napi_number); + break; + } + case JERRY_TYPE_STRING: { + NAPI_ASSIGN(result, napi_string); + break; + } + case JERRY_TYPE_SYMBOL: { + NAPI_ASSIGN(result, napi_symbol); + break; + } + case JERRY_TYPE_OBJECT: { + if (jerry_get_object_native_pointer(jval, NULL, + &napi_external_native_info)) { + NAPI_ASSIGN(result, napi_external); + } else { + NAPI_ASSIGN(result, napi_object); + } + break; + } + case JERRY_TYPE_FUNCTION: { + NAPI_ASSIGN(result, napi_function); + break; + } + default: + NAPI_RETURN(napi_invalid_arg); + } + + NAPI_RETURN(napi_ok); +} + +#define DEF_NAPI_VALUE_IS(type) \ + napi_status napi_is_##type(napi_env env, napi_value value, bool* result) { \ + NAPI_TRY_ENV(env); \ + return napi_assign_bool(jerry_value_is_##type(AS_JERRY_VALUE(value)), \ + result); \ + } + +DEF_NAPI_VALUE_IS(array); +DEF_NAPI_VALUE_IS(arraybuffer); +DEF_NAPI_VALUE_IS(dataview); +DEF_NAPI_VALUE_IS(typedarray); + +napi_status napi_is_buffer(napi_env env, napi_value value, bool* result) { + NAPI_TRY_ENV(env); + jerry_value_t jval_global = jerry_get_global_object(); + jerry_value_t jval_buffer = + iotjs_jval_get_property(jval_global, IOTJS_MAGIC_STRING_BUFFER); + + napi_status status = + napi_instanceof(env, value, AS_NAPI_VALUE(jval_buffer), result); + + jerry_release_value(jval_buffer); + jerry_release_value(jval_global); + + return status; +} + +napi_status napi_is_error(napi_env env, napi_value value, bool* result) { + NAPI_TRY_ENV(env); + jerry_value_t jval_global = jerry_get_global_object(); + jerry_value_t jval_error = + iotjs_jval_get_property(jval_global, IOTJS_MAGIC_STRING_ERROR); + + napi_status status = + napi_instanceof(env, value, AS_NAPI_VALUE(jval_error), result); + + jerry_release_value(jval_error); + jerry_release_value(jval_global); + + return status; +} + +napi_status napi_instanceof(napi_env env, napi_value object, + napi_value constructor, bool* result) { + NAPI_TRY_ENV(env); + jerry_value_t jval_object = AS_JERRY_VALUE(object); + jerry_value_t jval_cons = AS_JERRY_VALUE(constructor); + + jerry_value_t is_instance = + jerry_binary_operation(JERRY_BIN_OP_INSTANCEOF, jval_object, jval_cons); + if (jerry_value_is_error(is_instance)) { + jerry_release_value(is_instance); + NAPI_ASSIGN(result, false); + } else { + NAPI_ASSIGN(result, jerry_get_boolean_value(is_instance)); + } + + NAPI_RETURN(napi_ok); +} + +napi_status napi_strict_equals(napi_env env, napi_value lhs, napi_value rhs, + bool* result) { + NAPI_TRY_ENV(env); + jerry_value_t jval_lhs = AS_JERRY_VALUE(lhs); + jerry_value_t jval_rhs = AS_JERRY_VALUE(rhs); + + jerry_value_t is_equal = + jerry_binary_operation(JERRY_BIN_OP_STRICT_EQUAL, jval_lhs, jval_rhs); + if (jerry_value_is_error(is_equal)) { + jerry_release_value(is_equal); + NAPI_RETURN(napi_generic_failure); + } + + return napi_assign_bool(jerry_get_boolean_value(is_equal), result); +} + +napi_status napi_create_promise(napi_env env, napi_deferred* deferred, + napi_value* promise) { + NAPI_TRY_ENV(env); + if (!jerry_is_feature_enabled(JERRY_FEATURE_PROMISE)) { + NAPI_ASSIGN(promise, NULL); + NAPI_RETURN_WITH_MSG(napi_generic_failure, napi_err_no_promise); + } + + if (deferred == NULL) { + NAPI_ASSIGN(promise, NULL); + NAPI_RETURN_WITH_MSG(napi_generic_failure, napi_err_invalid_deferred); + } + + jerry_value_t jpromise = jerry_create_promise(); + napi_assign_nvalue(jpromise, promise); + *deferred = malloc(sizeof(napi_value*)); + memcpy(*deferred, promise, sizeof(napi_value*)); + NAPI_RETURN(napi_ok); +} + +napi_status napi_resolve_deferred(napi_env env, napi_deferred deferred, + napi_value resolution) { + NAPI_TRY_ENV(env); + if (!jerry_is_feature_enabled(JERRY_FEATURE_PROMISE)) { + NAPI_RETURN_WITH_MSG(napi_generic_failure, napi_err_no_promise); + } + + if (deferred == NULL) { + NAPI_RETURN_WITH_MSG(napi_generic_failure, napi_err_invalid_deferred); + } + + jerry_value_t promise = AS_JERRY_VALUE(*((napi_value*)deferred)); + jerry_value_t res = + jerry_resolve_or_reject_promise(promise, AS_JERRY_VALUE(resolution), + true); + jerry_release_value(promise); + free(deferred); + if (jerry_value_is_error(res)) { + NAPI_INTERNAL_CALL(napi_throw(env, AS_NAPI_VALUE(res))); + NAPI_RETURN(napi_pending_exception); + } + NAPI_RETURN(napi_ok); +} + +napi_status napi_reject_deferred(napi_env env, napi_deferred deferred, + napi_value rejection) { + NAPI_TRY_ENV(env); + if (!jerry_is_feature_enabled(JERRY_FEATURE_PROMISE)) { + NAPI_RETURN_WITH_MSG(napi_generic_failure, napi_err_no_promise); + } + + if (deferred == NULL) { + NAPI_RETURN_WITH_MSG(napi_generic_failure, napi_err_invalid_deferred); + } + + jerry_value_t promise = AS_JERRY_VALUE(*((napi_value*)deferred)); + jerry_value_t res = + jerry_resolve_or_reject_promise(promise, AS_JERRY_VALUE(rejection), + false); + jerry_release_value(promise); + free(deferred); + if (jerry_value_is_error(res)) { + NAPI_INTERNAL_CALL(napi_throw(env, AS_NAPI_VALUE(res))); + NAPI_RETURN(napi_pending_exception); + } + + NAPI_RETURN(napi_ok); +} + +napi_status napi_is_promise(napi_env env, napi_value promise, + bool* is_promise) { + NAPI_TRY_ENV(env); + if (!jerry_is_feature_enabled(JERRY_FEATURE_PROMISE)) { + NAPI_RETURN_WITH_MSG(napi_generic_failure, napi_err_no_promise); + } + + *is_promise = jerry_value_is_promise(AS_JERRY_VALUE(promise)); + NAPI_RETURN(napi_ok); +} diff --git a/src/napi/node_symbols.txt b/src/napi/node_symbols.txt new file mode 100644 index 0000000000..c6b40f2d10 --- /dev/null +++ b/src/napi/node_symbols.txt @@ -0,0 +1,111 @@ +napi_add_env_cleanup_hook +napi_async_destroy +napi_async_init +napi_call_function +napi_cancel_async_work +napi_close_callback_scope +napi_close_escapable_handle_scope +napi_close_handle_scope +napi_coerce_to_bool +napi_coerce_to_number +napi_coerce_to_object +napi_coerce_to_string +napi_create_array +napi_create_arraybuffer +napi_create_array_with_length +napi_create_async_work +napi_create_buffer +napi_create_buffer_copy +napi_create_dataview +napi_create_double +napi_create_error +napi_create_external +napi_create_external_arraybuffer +napi_create_external_buffer +napi_create_function +napi_create_int32 +napi_create_int64 +napi_create_object +napi_create_promise +napi_create_range_error +napi_create_reference +napi_create_string_utf8 +napi_create_symbol +napi_create_typedarray +napi_create_type_error +napi_create_uint32 +napi_define_class +napi_define_properties +napi_delete_async_work +napi_delete_element +napi_delete_property +napi_delete_reference +napi_escape_handle +napi_fatal_error +napi_fatal_exception +napi_get_and_clear_last_exception +napi_get_arraybuffer_info +napi_get_array_length +napi_get_boolean +napi_get_buffer_info +napi_get_cb_info +napi_get_dataview_info +napi_get_element +napi_get_global +napi_get_last_error_info +napi_get_named_property +napi_get_new_target +napi_get_node_version +napi_get_null +napi_get_property +napi_get_property_names +napi_get_prototype +napi_get_reference_value +napi_get_typedarray_info +napi_get_undefined +napi_get_uv_event_loop +napi_get_value_bool +napi_get_value_double +napi_get_value_external +napi_get_value_int32 +napi_get_value_int64 +napi_get_value_string_utf8 +napi_get_value_uint32 +napi_get_version +napi_has_element +napi_has_named_property +napi_has_own_property +napi_has_property +napi_instanceof +napi_is_array +napi_is_arraybuffer +napi_is_buffer +napi_is_dataview +napi_is_error +napi_is_exception_pending +napi_is_promise +napi_is_typedarray +napi_make_callback +napi_module_register +napi_new_instance +napi_open_callback_scope +napi_open_escapable_handle_scope +napi_open_handle_scope +napi_queue_async_work +napi_reference_ref +napi_reference_unref +napi_reject_deferred +napi_remove_env_cleanup_hook +napi_remove_wrap +napi_resolve_deferred +napi_set_element +napi_set_named_property +napi_set_property +napi_strict_equals +napi_throw +napi_throw_error +napi_throw_range_error +napi_throw_type_error +napi_typeof +napi_unwrap +napi_wrap diff --git a/iotjs_linux.c b/src/platform/linux/iotjs_linux.c similarity index 100% rename from iotjs_linux.c rename to src/platform/linux/iotjs_linux.c diff --git a/src/platform/linux/iotjs_module_i2c-linux.c b/src/platform/linux/iotjs_module_i2c-linux.c deleted file mode 100644 index c8e7731278..0000000000 --- a/src/platform/linux/iotjs_module_i2c-linux.c +++ /dev/null @@ -1,154 +0,0 @@ -/* The MIT License (MIT) - * - * Copyright (c) 2005-2014 RoadNarrows LLC. - * http://roadnarrows.com - * All Rights Reserved - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom - * the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -/* Copyright 2016-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. - */ - - -/* Some functions are modified from the RoadNarrows-robotics i2c library. - * (distributed under the MIT license.) - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include "modules/iotjs_module_i2c.h" - - -#define I2C_SLAVE_FORCE 0x0706 -#define I2C_SMBUS 0x0720 -#define I2C_SMBUS_READ 1 -#define I2C_SMBUS_WRITE 0 -#define I2C_NOCMD 0 -#define I2C_SMBUS_BYTE 1 -#define I2C_SMBUS_BLOCK_DATA 5 -#define I2C_SMBUS_I2C_BLOCK_DATA 8 -#define I2C_SMBUS_BLOCK_MAX 32 -#define I2C_MAX_ADDRESS 128 - - -typedef union I2cSmbusDataUnion { - uint8_t byte; - unsigned short word; - uint8_t block[I2C_SMBUS_BLOCK_MAX + 2]; -} I2cSmbusData; - - -typedef struct I2cSmbusIoctlDataStruct { - uint8_t read_write; - uint8_t command; - int size; - I2cSmbusData* data; -} I2cSmbusIoctlData; - - -#define I2C_WORKER_INIT_TEMPLATE \ - iotjs_i2c_reqwrap_t* req_wrap = iotjs_i2c_reqwrap_from_request(work_req); \ - iotjs_i2c_reqdata_t* req_data = iotjs_i2c_reqwrap_data(req_wrap); - - -void I2cSetAddress(iotjs_i2c_t* i2c, uint8_t address) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_i2c_t, i2c); - _this->addr = address; - ioctl(_this->device_fd, I2C_SLAVE_FORCE, _this->addr); -} - - -void OpenWorker(uv_work_t* work_req) { - I2C_WORKER_INIT_TEMPLATE; - iotjs_i2c_t* i2c = iotjs_i2c_instance_from_reqwrap(req_wrap); - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_i2c_t, i2c); - - _this->device_fd = open(iotjs_string_data(&req_data->device), O_RDWR); - - if (_this->device_fd == -1) { - req_data->error = kI2cErrOpen; - } else { - req_data->error = kI2cErrOk; - } -} - - -void I2cClose(iotjs_i2c_t* i2c) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_i2c_t, i2c); - - if (_this->device_fd > 0) { - close(_this->device_fd); - _this->device_fd = -1; - } -} - - -void WriteWorker(uv_work_t* work_req) { - I2C_WORKER_INIT_TEMPLATE; - iotjs_i2c_t* i2c = iotjs_i2c_instance_from_reqwrap(req_wrap); - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_i2c_t, i2c); - - uint8_t len = req_data->buf_len; - char* data = req_data->buf_data; - - if (write(_this->device_fd, data, len) != len) { - req_data->error = kI2cErrWrite; - } - - if (req_data->buf_data != NULL) { - iotjs_buffer_release(req_data->buf_data); - } -} - - -void ReadWorker(uv_work_t* work_req) { - I2C_WORKER_INIT_TEMPLATE; - iotjs_i2c_t* i2c = iotjs_i2c_instance_from_reqwrap(req_wrap); - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_i2c_t, i2c); - - uint8_t len = req_data->buf_len; - req_data->buf_data = iotjs_buffer_allocate(len); - - if (read(_this->device_fd, req_data->buf_data, len) != len) { - req_data->error = kI2cErrRead; - } -} diff --git a/src/platform/linux/iotjs_module_spi-linux.c b/src/platform/linux/iotjs_module_spi-linux.c deleted file mode 100644 index 338c01889e..0000000000 --- a/src/platform/linux/iotjs_module_spi-linux.c +++ /dev/null @@ -1,169 +0,0 @@ -/* Copyright 2016-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_SPI_LINUX_GENERAL_INL_H -#define IOTJS_MODULE_SPI_LINUX_GENERAL_INL_H - - -#include -#include -#include - -#include "iotjs_def.h" -#include "iotjs_systemio-linux.h" -#include "modules/iotjs_module_buffer.h" -#include "modules/iotjs_module_spi.h" - -#define ADC_DEVICE_PATH_FORMAT "/dev/spidev%d.%d" -#define ADC_DEVICE_PATH_BUFFER_SIZE 16 - - -static bool iotjs_spi_set_configuration(iotjs_spi_t* spi) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_spi_t, spi); - - int fd = _this->device_fd; - if (fd < 0) { - return false; - } - - uint8_t data; - - switch (_this->mode) { - case kSpiMode_0: - data = SPI_MODE_0; - break; - case kSpiMode_1: - data = SPI_MODE_1; - break; - case kSpiMode_2: - data = SPI_MODE_2; - break; - case kSpiMode_3: - data = SPI_MODE_3; - break; - default: - data = SPI_MODE_0; - } - if (_this->loopback) { - data |= SPI_LOOP; - } - - if (_this->chip_select == kSpiCsHigh) { - data |= SPI_CS_HIGH; - } - - if (ioctl(fd, SPI_IOC_WR_MODE, &_this->mode) < 0) { - return false; - } - - - if (_this->bit_order == kSpiOrderLsb) { - data = 1; - if (ioctl(fd, SPI_IOC_WR_LSB_FIRST, &data) < 0) { - return false; - } - } - - if (ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &_this->bits_per_word) < 0) { - return false; - } - - if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &_this->max_speed) < 0) { - return false; - } - - DDLOG( - "SPI Options \n mode: %d\n chipSelect: %d\n bitOrder: %d\n " - "maxSpeed: %d\n bitPerWord: %d\n loopback: %d", - _this->mode, _this->chip_select, _this->bit_order, _this->max_speed, - _this->bits_per_word, _this->loopback); - - return true; -} - - -bool iotjs_spi_transfer(iotjs_spi_t* spi) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_spi_t, spi); - - struct spi_ioc_transfer data = {.tx_buf = (unsigned long)_this->tx_buf_data, - .rx_buf = (unsigned long)_this->rx_buf_data, - .len = _this->buf_len, - .speed_hz = _this->max_speed, - .bits_per_word = _this->bits_per_word, - .delay_usecs = 0 }; - - // Transfer data - int err = ioctl(_this->device_fd, SPI_IOC_MESSAGE(1), &data); - if (err < 1) { - DDLOG("%s - transfer failed: %d", __func__, err); - return false; - } - - return true; -} - - -bool iotjs_spi_close(iotjs_spi_t* spi) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_spi_t, spi); - - if (_this->device_fd >= 0) { - const iotjs_environment_t* env = iotjs_environment_get(); - uv_loop_t* loop = iotjs_environment_loop(env); - uv_fs_t fs_close_req; - - int err = uv_fs_close(loop, &fs_close_req, _this->device_fd, NULL); - uv_fs_req_cleanup(&fs_close_req); - if (err < 0) { - DDLOG("%s - close failed: %d", __func__, err); - return false; - } - _this->device_fd = -1; - } - - return true; -} - - -void iotjs_spi_open_worker(uv_work_t* work_req) { - SPI_WORKER_INIT; - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_spi_t, spi); - - const char* device_path = iotjs_string_data(&_this->device); - if (iotjs_systemio_check_path(device_path)) { - // Open file - const iotjs_environment_t* env = iotjs_environment_get(); - uv_loop_t* loop = iotjs_environment_loop(env); - - uv_fs_t open_req; - int result = uv_fs_open(loop, &open_req, device_path, O_RDONLY, 0666, NULL); - uv_fs_req_cleanup(&open_req); - if (result < 0) { - req_data->result = false; - } - _this->device_fd = open_req.result; - - // Set options - if (!iotjs_spi_set_configuration(spi)) { - req_data->result = false; - return; - } - req_data->result = true; - } else { - req_data->result = false; - } -} - - -#endif /* IOTJS_MODULE_SPI_LINUX_GENERAL_INL_H */ diff --git a/src/platform/linux/iotjs_systemio-linux.c b/src/platform/linux/iotjs_systemio-linux.c index 452bbbffa6..029a6761b5 100644 --- a/src/platform/linux/iotjs_systemio-linux.c +++ b/src/platform/linux/iotjs_systemio-linux.c @@ -53,7 +53,7 @@ bool iotjs_systemio_open_write_close(const char* path, const char* value) { int fd = uv_fs_open(loop, &fs_req, path, O_WRONLY, 0666, NULL); uv_fs_req_cleanup(&fs_req); if (fd < 0) { - DDLOG("%s - open %s failed: %d", __func__, path, fd); + DLOG("%s - open %s failed: %d", __func__, path, fd); return false; } @@ -68,12 +68,12 @@ bool iotjs_systemio_open_write_close(const char* path, const char* value) { uv_fs_req_cleanup(&fs_req); if (write_err < 0) { - DDLOG("%s - write %s %s failed: %d", __func__, path, value, write_err); + DLOG("%s - write %s %s failed: %d", __func__, path, value, write_err); return false; } if (close_err < 0) { - DDLOG("%s - close failed: %d", __func__, close_err); + DLOG("%s - close failed: %d", __func__, close_err); return false; } @@ -93,7 +93,7 @@ bool iotjs_systemio_open_read_close(const char* path, char* buffer, int fd = uv_fs_open(loop, &fs_open_req, path, O_RDONLY, 0666, NULL); uv_fs_req_cleanup(&fs_open_req); if (fd < 0) { - DDLOG("%s - open %s failed: %d", __func__, path, fd); + DLOG("%s - open %s failed: %d", __func__, path, fd); return false; } @@ -103,7 +103,7 @@ bool iotjs_systemio_open_read_close(const char* path, char* buffer, int err = uv_fs_read(loop, &fs_write_req, fd, &uvbuf, 1, 0, NULL); uv_fs_req_cleanup(&fs_write_req); if (err < 0) { - DDLOG("%s - read failed: %d", __func__, err); + DLOG("%s - read failed: %d", __func__, err); return false; } @@ -114,7 +114,7 @@ bool iotjs_systemio_open_read_close(const char* path, char* buffer, err = uv_fs_close(loop, &fs_close_req, fd, NULL); uv_fs_req_cleanup(&fs_close_req); if (err < 0) { - DDLOG("%s - close failed: %d", __func__, err); + DLOG("%s - close failed: %d", __func__, err); return false; } @@ -132,7 +132,7 @@ bool iotjs_systemio_device_open(const char* export_path, uint32_t value, return true; } - DDLOG("%s - path: %s", __func__, export_path); + DDDLOG("%s - path: %s", __func__, export_path); // Write export pin. char buff[DEVICE_IO_PIN_BUFFER_SIZE] = { 0 }; @@ -147,21 +147,17 @@ bool iotjs_systemio_device_open(const char* export_path, uint32_t value, int count_limit = created_files_length * 10; char buffer[DEVICE_IO_PIN_BUFFER_SIZE]; char path[DEVICE_IO_PATH_BUFFER_SIZE] = { 0 }; - char check_format[DEVICE_IO_PATH_BUFFER_SIZE] = { 0 }; while (!iotjs_systemio_check_path(exported_path) && count < count_limit) { usleep(100 * 1000); // sleep 100 miliseconds. count++; } - strcat(check_format, exported_path); - strcat(check_format, "%s"); - for (int i = 0; i < created_files_length; i++) { - snprintf(path, DEVICE_IO_PATH_BUFFER_SIZE - 1, check_format, + snprintf(path, DEVICE_IO_PATH_BUFFER_SIZE - 1, "%s%s", exported_path, created_files[i]); - DDLOG("%s - created file: %s", __func__, path); + DDDLOG("%s - created file: %s", __func__, path); while (!iotjs_systemio_open_read_close(path, buffer, DEVICE_IO_PIN_BUFFER_SIZE) && diff --git a/src/platform/linux/iotjs_systemio-linux.h b/src/platform/linux/iotjs_systemio-linux.h index 8ec7855b45..f00b7ff175 100644 --- a/src/platform/linux/iotjs_systemio-linux.h +++ b/src/platform/linux/iotjs_systemio-linux.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef IOTJS_DEVICE_IO_LINUX_GENERAL_H -#define IOTJS_DEVICE_IO_LINUX_GENERAL_H +#ifndef IOTJS_SYSTEMIO_LINUX_H +#define IOTJS_SYSTEMIO_LINUX_H #include "iotjs_def.h" @@ -37,4 +37,4 @@ bool iotjs_systemio_device_open(const char* export_path, uint32_t value, bool iotjs_systemio_device_close(const char* export_path, uint32_t value); -#endif /* IOTJS_DEVICE_IO_LINUX_GENERAL_H */ +#endif /* IOTJS_SYSTEMIO_LINUX_H */ diff --git a/src/platform/nuttx/iotjs_module_i2c-nuttx.c b/src/platform/nuttx/iotjs_module_i2c-nuttx.c deleted file mode 100644 index 14dcfe990c..0000000000 --- a/src/platform/nuttx/iotjs_module_i2c-nuttx.c +++ /dev/null @@ -1,112 +0,0 @@ -/* Copyright 2016-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 defined(__NUTTX__) - -#include "iotjs_systemio-nuttx.h" - -#include "modules/iotjs_module_i2c.h" - - -#define I2C_DEFAULT_FREQUENCY 400000 - - -void I2cSetAddress(iotjs_i2c_t* i2c, uint8_t address) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_i2c_t, i2c); - _this->config.address = address; - _this->config.addrlen = 7; -} - - -#define I2C_WORKER_INIT_TEMPLATE \ - iotjs_i2c_reqwrap_t* req_wrap = iotjs_i2c_reqwrap_from_request(work_req); \ - iotjs_i2c_reqdata_t* req_data = iotjs_i2c_reqwrap_data(req_wrap); - - -void OpenWorker(uv_work_t* work_req) { - I2C_WORKER_INIT_TEMPLATE; - iotjs_i2c_t* i2c = iotjs_i2c_instance_from_reqwrap(req_wrap); - - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_i2c_t, i2c); - _this->i2c_master = iotjs_i2c_config_nuttx(req_data->device); - if (!_this->i2c_master) { - DDLOG("I2C OpenWorker : cannot open"); - req_data->error = kI2cErrOpen; - return; - } - - _this->config.frequency = I2C_DEFAULT_FREQUENCY; - - req_data->error = kI2cErrOk; -} - - -void I2cClose(iotjs_i2c_t* i2c) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_i2c_t, i2c); - - iotjs_i2c_unconfig_nuttx(_this->i2c_master); -} - - -void WriteWorker(uv_work_t* work_req) { - I2C_WORKER_INIT_TEMPLATE; - iotjs_i2c_t* i2c = iotjs_i2c_instance_from_reqwrap(req_wrap); - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_i2c_t, i2c); - - uint8_t len = req_data->buf_len; - uint8_t* data = (uint8_t*)req_data->buf_data; - - IOTJS_ASSERT(_this->i2c_master); - IOTJS_ASSERT(len > 0); - - int ret = i2c_write(_this->i2c_master, &_this->config, data, len); - if (ret < 0) { - DDLOG("I2C WriteWorker : cannot write - %d", ret); - req_data->error = kI2cErrWrite; - } else { - req_data->error = kI2cErrOk; - } - - if (req_data->buf_data != NULL) { - iotjs_buffer_release(req_data->buf_data); - } - - req_data->error = kI2cErrOk; -} - - -void ReadWorker(uv_work_t* work_req) { - I2C_WORKER_INIT_TEMPLATE; - iotjs_i2c_t* i2c = iotjs_i2c_instance_from_reqwrap(req_wrap); - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_i2c_t, i2c); - - uint8_t len = req_data->buf_len; - req_data->buf_data = iotjs_buffer_allocate(len); - - IOTJS_ASSERT(_this->i2c_master); - IOTJS_ASSERT(len > 0); - - int ret = i2c_read(_this->i2c_master, &_this->config, - (uint8_t*)req_data->buf_data, len); - if (ret != 0) { - DDLOG("I2C ReadWorker : cannot read - %d", ret); - req_data->error = kI2cErrRead; - return; - } - req_data->error = kI2cErrOk; -} - - -#endif // __NUTTX__ diff --git a/src/platform/nuttx/iotjs_module_spi-nuttx.c b/src/platform/nuttx/iotjs_module_spi-nuttx.c deleted file mode 100644 index 03fc12cc77..0000000000 --- a/src/platform/nuttx/iotjs_module_spi-nuttx.c +++ /dev/null @@ -1,48 +0,0 @@ -/* Copyright 2016-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 defined(__NUTTX__) - - -#include "modules/iotjs_module_spi.h" - - -bool iotjs_spi_transfer(iotjs_spi_t* spi) { - IOTJS_ASSERT(!"Not implemented"); - return false; -} - - -bool iotjs_spi_close(iotjs_spi_t* spi) { - IOTJS_ASSERT(!"Not implemented"); - return false; -} - -void iotjs_spi_open_worker(uv_work_t* work_req) { - IOTJS_ASSERT(!"Not implemented"); -} - - -void iotjs_spi_transfer_worker(uv_work_t* work_req) { - IOTJS_ASSERT(!"Not implemented"); -} - - -void iotjs_spi_close_worker(uv_work_t* work_req) { - IOTJS_ASSERT(!"Not implemented"); -} - - -#endif // __NUTTX__ diff --git a/src/platform/nuttx/iotjs_module_uart-nuttx.c b/src/platform/nuttx/iotjs_module_uart-nuttx.c deleted file mode 100644 index ff42bcf411..0000000000 --- a/src/platform/nuttx/iotjs_module_uart-nuttx.c +++ /dev/null @@ -1,78 +0,0 @@ -/* Copyright 2016-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 defined(__NUTTX__) - - -#include "modules/iotjs_module_uart.h" - - -void iotjs_uart_open_worker(uv_work_t* work_req) { - UART_WORKER_INIT; - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_uart_t, uart); - - int fd = open(iotjs_string_data(&_this->device_path), - O_RDWR | O_NOCTTY | O_NDELAY); - - if (fd < 0) { - req_data->result = false; - return; - } - - _this->device_fd = fd; - uv_poll_t* poll_handle = &_this->poll_handle; - - uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get()); - uv_poll_init(loop, poll_handle, fd); - poll_handle->data = uart; - uv_poll_start(poll_handle, UV_READABLE, iotjs_uart_read_cb); - - req_data->result = true; -} - - -bool iotjs_uart_write(iotjs_uart_t* uart) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_uart_t, uart); - int bytesWritten = 0; - unsigned offset = 0; - int fd = _this->device_fd; - const char* buf_data = iotjs_string_data(&_this->buf_data); - - DDDLOG("%s - data: %s", __func__, buf_data); - - do { - errno = 0; - bytesWritten = write(fd, buf_data + offset, _this->buf_len - offset); - - DDDLOG("%s - size: %d", __func__, _this->buf_len - offset); - - if (bytesWritten != -1) { - offset += (unsigned)bytesWritten; - continue; - } - - if (errno == EINTR) { - continue; - } - - return false; - - } while (_this->buf_len > offset); - - return true; -} - - -#endif // __NUTTX__ diff --git a/src/platform/nuttx/stm32f4dis/iotjs_systemio-nuttx-stm32f4dis.c b/src/platform/nuttx/iotjs_systemio-nuttx.c similarity index 70% rename from src/platform/nuttx/stm32f4dis/iotjs_systemio-nuttx-stm32f4dis.c rename to src/platform/nuttx/iotjs_systemio-nuttx.c index 1501b2bbbe..1305762e60 100644 --- a/src/platform/nuttx/stm32f4dis/iotjs_systemio-nuttx-stm32f4dis.c +++ b/src/platform/nuttx/iotjs_systemio-nuttx.c @@ -13,19 +13,30 @@ * limitations under the License. */ -#if defined(__NUTTX__) && TARGET_BOARD == STM32F4DIS +#if defined(__NUTTX__) && (defined(TARGET_BOARD_STM32F4DIS) || \ + (defined(TARGET_BOARD_STM32F7NUCLEO))) #include -#include "../iotjs_systemio-nuttx.h" +#include "iotjs_systemio-nuttx.h" #include "stm32_gpio.h" +void iotjs_gpio_config_nuttx(uint32_t pin) { + stm32_configgpio(pin); +} + + void iotjs_gpio_unconfig_nuttx(uint32_t pin) { stm32_unconfiggpio(pin); } +void iotjs_gpio_write_nuttx(uint32_t pin, bool value) { + stm32_gpiowrite(pin, value); +} + + #if ENABLE_MODULE_ADC #include "stm32_adc.h" @@ -34,7 +45,11 @@ struct adc_dev_s* iotjs_adc_config_nuttx(int number, int timer, uint32_t pin) { stm32_configgpio(pin); uint8_t channel_list[1] = { timer }; +#if defined(TARGET_BOARD_STM32F4DIS) return stm32_adcinitialize(number, channel_list, 1); +#elif defined(TARGET_BOARD_STM32F7NUCLEO) + return stm32_adc_initialize(number, channel_list, 1); +#endif } #endif /* ENABLE_MODULE_ADC */ @@ -71,4 +86,17 @@ struct pwm_lowerhalf_s* iotjs_pwm_config_nuttx(int timer, uint32_t pin) { #endif /* ENABLE_MODULE_PWM */ +#if ENABLE_MODULE_SPI + +#include "stm32_spi.h" + +struct spi_dev_s* iotjs_spi_config_nuttx(int bus, uint32_t cs_chip) { + stm32_configgpio(cs_chip); + + return stm32_spibus_initialize(bus); +} + +#endif /* ENABLE_MODULE_SPI */ + + #endif // __NUTTX__ diff --git a/src/platform/nuttx/iotjs_systemio-nuttx.h b/src/platform/nuttx/iotjs_systemio-nuttx.h index d20208f69d..31eb08c4db 100644 --- a/src/platform/nuttx/iotjs_systemio-nuttx.h +++ b/src/platform/nuttx/iotjs_systemio-nuttx.h @@ -13,12 +13,16 @@ * limitations under the License. */ -#ifndef IOTJS_SYSTEMIO_ARM_NUTTX_H -#define IOTJS_SYSTEMIO_ARM_NUTTX_H +#ifndef IOTJS_SYSTEMIO_NUTTX_H +#define IOTJS_SYSTEMIO_NUTTX_H #include +#include "iotjs_def.h" + +void iotjs_gpio_config_nuttx(uint32_t pin); void iotjs_gpio_unconfig_nuttx(uint32_t pin); +void iotjs_gpio_write_nuttx(uint32_t pin, bool value); #if ENABLE_MODULE_ADC || ENABLE_MODULE_PWM @@ -65,4 +69,13 @@ struct pwm_lowerhalf_s* iotjs_pwm_config_nuttx(int timer, uint32_t pin); #endif /* ENABLE_MODULE_PWM */ -#endif /* IOTJS_SYSTEMIO_ARM_NUTTX_H */ +#if ENABLE_MODULE_SPI + +#include + +struct spi_dev_s* iotjs_spi_config_nuttx(int bus, uint32_t cs_chip); + +#endif /* ENABLE_MODULE_SPI */ + + +#endif /* IOTJS_SYSTEMIO_NUTTX_H */ diff --git a/src/platform/tizen/iotjs_tizen_service_app.c b/src/platform/tizen/iotjs_tizen_service_app.c new file mode 100644 index 0000000000..7be1656e5f --- /dev/null +++ b/src/platform/tizen/iotjs_tizen_service_app.c @@ -0,0 +1,197 @@ +/* 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 +#include +#include +#include +#include + +#include "iotjs_def.h" +#include "iotjs.h" + +extern bool iotjs_initialize(iotjs_environment_t* env); +extern void iotjs_run(iotjs_environment_t* env); +extern void iotjs_end(iotjs_environment_t* env); +extern void iotjs_terminate(iotjs_environment_t* env); + +static char js_absolute_path[128]; +static GMainLoop* gmain_loop; +static bool is_env_initialized = false; + +typedef struct { + GSource source; + iotjs_environment_t* env; +} iotjs_gmain_source_t; + +static int console_log(int level, const char* format, ...) { + va_list args; + va_start(args, format); + dlog_vprint(DLOG_INFO, "IOTJS", format, args); + va_end(args); + return 0; +} + +static gboolean gmain_loop_check(GSource* source) { + return TRUE; +} + +static gboolean gmain_loop_dispatch(GSource* source, GSourceFunc callback, + gpointer user_data) { + iotjs_environment_t* env = ((iotjs_gmain_source_t*)source)->env; + + bool more = uv_run(iotjs_environment_loop(env), UV_RUN_NOWAIT); + more |= iotjs_process_next_tick(); + + jerry_value_t ret_val = jerry_run_all_enqueued_jobs(); + if (jerry_value_is_error(ret_val)) { + DLOG("jerry_run_all_enqueued_jobs() failed"); + } + + if (more == false) { + more = uv_loop_alive(iotjs_environment_loop(env)); + } + + if (!more || iotjs_environment_is_exiting(env)) { + service_app_exit(); + return false; + } + return true; +} + +static void loop_method_init_cb(int argc, char** argv, void* data) { + int iotjs_argc = 2; + char* iotjs_argv[2] = { "iotjs", js_absolute_path }; + +#ifdef ENABLE_DEBUG_LOG + setenv("IOTJS_DEBUG_LEVEL", "3", 0); // Enable all log. +#endif + + // Initialize debug log and environments + iotjs_debuglog_init(); + + iotjs_environment_t* env = iotjs_environment_get(); + + if (!iotjs_environment_parse_command_line_arguments(env, (uint32_t)iotjs_argc, + iotjs_argv)) { + service_app_exit(); + return; + } + is_env_initialized = true; + + if (!iotjs_initialize(env)) { + DLOG("iotjs_initialize failed"); + service_app_exit(); + return; + } + + DDDLOG("%s", __func__); + + iotjs_conf_console_out(console_log); +} + +static void loop_method_run_cb(void* data) { + DDDLOG("%s", __func__); + iotjs_environment_t* env = iotjs_environment_get(); + iotjs_environment_set_state(env, kRunningMain); + + // Load and call iotjs.js. + iotjs_run(env); + + if (iotjs_environment_is_exiting(env)) { + service_app_exit(); + return; + } + + // Create GMain loop. + gmain_loop = g_main_loop_new(g_main_context_default(), FALSE); + + // Add GSource in GMain context. + GSourceFuncs source_funcs = { + .check = gmain_loop_check, .dispatch = gmain_loop_dispatch, + }; + + iotjs_gmain_source_t* source = + (iotjs_gmain_source_t*)g_source_new(&source_funcs, + sizeof(iotjs_gmain_source_t)); + source->env = env; + uv_loop_t* uv_loop = iotjs_environment_loop(env); + g_source_add_unix_fd(&source->source, uv_loop->backend_fd, + (GIOCondition)(G_IO_IN | G_IO_OUT | G_IO_ERR)); + g_source_attach(&source->source, g_main_context_default()); + + iotjs_environment_set_state(env, kRunningLoop); + + g_main_loop_run(gmain_loop); // Blocks until loop is quit. + + + if (!iotjs_environment_is_exiting(env)) { + // Emit 'exit' event. + iotjs_process_emit_exit(iotjs_process_exitcode()); + + iotjs_environment_set_state(env, kExiting); + } + + DDDLOG("%s: Exit IoT.js(%d).", __func__, iotjs_process_exitcode()); + + iotjs_end(env); +} + +static void loop_method_exit_cb(void* data) { + DDDLOG("%s", __func__); + + if (g_main_loop_is_running(gmain_loop)) { + g_main_loop_quit(gmain_loop); + g_main_loop_unref(gmain_loop); + } +} + +static void loop_method_fini_cb(void) { + DDDLOG("%s", __func__); + iotjs_environment_t* env = iotjs_environment_get(); + + if (is_env_initialized) { + iotjs_terminate(env); + } + + iotjs_environment_release(); + iotjs_debuglog_release(); +} + +int iotjs_service_app_start(int argc, char** argv, char* js_path, + void* event_callbacks, void* user_data) { + DDDLOG("%s", __func__); + char* app_res_path = app_get_resource_path(); + if (!app_res_path) { + DLOG("app_res_path is NULL!"); + 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, + .run = loop_method_run_cb, + .exit = loop_method_exit_cb, + .fini = loop_method_fini_cb }; + + return service_app_main_ext(argc, argv, (service_app_lifecycle_callback_s*) + event_callbacks, + &loop_method, user_data); +} diff --git a/src/platform/tizen/iotjs_tizen_service_app.h b/src/platform/tizen/iotjs_tizen_service_app.h new file mode 100644 index 0000000000..7c6932286d --- /dev/null +++ b/src/platform/tizen/iotjs_tizen_service_app.h @@ -0,0 +1,50 @@ +/* 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_TIZEN_SERVICE_APP_H +#define IOTJS_TIZEN_SERVICE_APP_H + +#include +#include + +#ifdef __cplusplus +#define IOTJS_EXTERN_C extern "C" +#else /* !__cplusplus */ +#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/src/platform/tizenrt/iotjs_main_tizenrt.c b/src/platform/tizenrt/iotjs_main_tizenrt.c new file mode 100644 index 0000000000..9c7e4709fd --- /dev/null +++ b/src/platform/tizenrt/iotjs_main_tizenrt.c @@ -0,0 +1,256 @@ +/* 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. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include +#include +#include +#ifdef JERRY_DEBUGGER +#include +#endif /* JERRY_DEBUGGER */ + +#include "jerryscript-port.h" +#include "jerryscript.h" + +#define USE_IOTJS_THREAD 1 + +/** + * Aborts the program. + */ +void jerry_port_fatal(jerry_fatal_code_t code) { + exit(1); +} /* jerry_port_fatal */ + +/** + * Provide log message implementation for the engine. + */ +void jerry_port_log(jerry_log_level_t level, /**< log level */ + const char *format, /**< format string */ + ...) { /**< parameters */ + /* Drain log messages since IoT.js has not support log levels yet. */ +} /* jerry_port_log */ + +/** + * Dummy function to get local time zone adjustment, in milliseconds, + * for the given timestamp. + */ +double jerry_port_get_local_time_zone_adjustment(double unix_ms, bool is_utc) { + (void)unix_ms; + (void)is_utc; + return 0.0; +} /* jerry_port_get_local_time_zone_adjustment */ + +/** + * Get system time + * + * @return milliseconds since Unix epoch + */ +double jerry_port_get_current_time(void) { + struct timespec ts; + + /* Get the current time */ + int ret = clock_gettime(CLOCK_REALTIME, &ts); + if (ret < 0) { + return 0.0; + } + + return ((double)ts.tv_sec) * 1000.0 + ((double)ts.tv_nsec) / 1000000.0; +} /* jerry_port_get_current_time */ + +/** + * Provide the implementation of jerryx_port_handler_print_char. + * Uses 'printf' to print a single character to standard output. + */ +void jerryx_port_handler_print_char(char c) { /**< the character to print */ + // printf("%c", c); +} /* jerryx_port_handler_print_char */ + +/** + * Determines the size of the given file. + * @return size of the file + */ +static size_t jerry_port_get_file_size(FILE *file_p) /**< opened file */ +{ + fseek(file_p, 0, SEEK_END); + long size = ftell(file_p); + fseek(file_p, 0, SEEK_SET); + + return (size_t)size; +} /* jerry_port_get_file_size */ + +/** + * Opens file with the given path and reads its source. + * @return the source of the file + */ +uint8_t *jerry_port_read_source(const char *file_name_p, /**< file name */ + size_t *out_size_p) /**< [out] read bytes */ +{ + FILE *file_p = fopen(file_name_p, "rb"); + + if (file_p == NULL) { + jerry_port_log(JERRY_LOG_LEVEL_ERROR, "Error: failed to open file: %s\n", + file_name_p); + return NULL; + } + + size_t file_size = jerry_port_get_file_size(file_p); + uint8_t *buffer_p = (uint8_t *)malloc(file_size); + + if (buffer_p == NULL) { + fclose(file_p); + + jerry_port_log(JERRY_LOG_LEVEL_ERROR, + "Error: failed to allocate memory for module"); + return NULL; + } + + size_t bytes_read = fread(buffer_p, 1u, file_size, file_p); + + if (!bytes_read) { + fclose(file_p); + free(buffer_p); + + jerry_port_log(JERRY_LOG_LEVEL_ERROR, "Error: failed to read file: %s\n", + file_name_p); + return NULL; + } + + fclose(file_p); + *out_size_p = bytes_read; + + return buffer_p; +} /* jerry_port_read_source */ + +/** + * Release the previously opened file's content. + */ +void jerry_port_release_source(uint8_t *buffer_p) /**< buffer to free */ +{ + free(buffer_p); +} /* jerry_port_release_source */ + +/** + * Normalize a file path + * + * @return length of the path written to the output buffer + */ +size_t jerry_port_normalize_path( + const char *in_path_p, /**< input file path */ + char *out_buf_p, /**< output buffer */ + size_t out_buf_size) /**< size of output buffer */ +{ + size_t len = strlen(in_path_p); + if (len + 1 > out_buf_size) { + return 0; + } + + /* Return the original string. */ + strcpy(out_buf_p, in_path_p); + return len; +} /* jerry_port_normalize_path */ + +#ifdef JERRY_DEBUGGER +void jerry_port_sleep(uint32_t sleep_time) { + nanosleep( + &(const struct timespec){ + (time_t)sleep_time / 1000, + ((long int)sleep_time % 1000) * 1000000L /* Seconds, nanoseconds */ + }, + NULL); +} /* jerry_port_sleep */ +#endif /* JERRY_DEBUGGER */ + +int iotjs_entry(int argc, char **argv); +int tuv_cleanup(void); + + +#if USE_IOTJS_THREAD +struct iotjs_thread_arg { + int argc; + char **argv; +}; + +pthread_addr_t iotjs_thread(void *thread_arg) { + struct iotjs_thread_arg *arg = thread_arg; + +#ifdef CONFIG_DEBUG_VERBOSE + int ret = iotjs_entry(arg->argc, arg->argv); + printf("IoT.js Result: %d\n", ret); +#else + iotjs_entry(arg->argc, arg->argv); +#endif + tuv_cleanup(); + + sleep(1); + return NULL; +} + +int iotjs(int argc, char *argv[]) { + pthread_attr_t attr; + int status; + struct sched_param sparam; + pthread_t tid = (pthread_t)0; + struct iotjs_thread_arg arg; + + status = pthread_attr_init(&attr); + if (status != 0) { + printf("fail to initialize iotjs thread\n"); + return -1; + } + + sparam.sched_priority = CONFIG_IOTJS_PRIORITY; + status = pthread_attr_setschedparam(&attr, &sparam); + status = pthread_attr_setschedpolicy(&attr, SCHED_RR); + status = pthread_attr_setstacksize(&attr, CONFIG_IOTJS_STACKSIZE); + + arg.argc = argc; + arg.argv = argv; + + status = pthread_create(&tid, &attr, iotjs_thread, &arg); + if (status < 0) { + printf("fail to start iotjs thread\n"); + return -1; + } + pthread_setname_np(tid, "iotjs_thread"); + pthread_join(tid, NULL); + + return 0; +} + +#else + +static int iotjs(int argc, char *argv[]) { + int ret = 0; + ret = iotjs_entry(argc, argv); +#ifdef CONFIG_DEBUG_VERBOSE + printf("IoT.js Result: %d\n", ret); +#endif + tuv_cleanup(); + return ret; +} + +#endif + +int iotjs_register_cmds(void) { + tash_cmd_install("iotjs", iotjs, TASH_EXECMD_SYNC); + return 0; +} diff --git a/src/platform/tizenrt/iotjs_module_gpio-tizenrt.c b/src/platform/tizenrt/iotjs_module_gpio-tizenrt.c deleted file mode 100644 index 18d7312724..0000000000 --- a/src/platform/tizenrt/iotjs_module_gpio-tizenrt.c +++ /dev/null @@ -1,76 +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. - */ - - -#include "modules/iotjs_module_gpio.h" - - -void iotjs_gpio_open_worker(uv_work_t* work_req) { - GPIO_WORKER_INIT; - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_gpio_t, gpio); - - DDDLOG("%s - pin: %d, direction: %d, mode: %d", __func__, _this->pin, - _this->direction, _this->mode); - - // Open gpio pin - _this->gpio_context = iotbus_gpio_open(_this->pin); - if (_this->gpio_context == NULL) { - req_data->result = false; - return; - } - - // Set direction - iotbus_gpio_direction_e direction; - if (_this->direction == kGpioDirectionIn) { - direction = IOTBUS_GPIO_DIRECTION_IN; - } else if (_this->direction == kGpioDirectionOut) { - direction = IOTBUS_GPIO_DIRECTION_OUT; - } else { - direction = IOTBUS_GPIO_DIRECTION_NONE; - } - if (iotbus_gpio_set_direction(_this->gpio_context, direction) < 0) { - req_data->result = false; - return; - } - - req_data->result = true; -} - - -bool iotjs_gpio_write(iotjs_gpio_t* gpio, bool value) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_gpio_t, gpio); - - if (iotbus_gpio_write(_this->gpio_context, value) < 0) { - return false; - } - return true; -} - - -int iotjs_gpio_read(iotjs_gpio_t* gpio) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_gpio_t, gpio); - - return iotbus_gpio_read(_this->gpio_context); -} - - -bool iotjs_gpio_close(iotjs_gpio_t* gpio) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_gpio_t, gpio); - - if (iotbus_gpio_close(_this->gpio_context) < 0) { - return false; - } - return true; -} diff --git a/src/platform/tizenrt/iotjs_module_pwm-tizenrt.c b/src/platform/tizenrt/iotjs_module_pwm-tizenrt.c deleted file mode 100644 index ff6e3c1d48..0000000000 --- a/src/platform/tizenrt/iotjs_module_pwm-tizenrt.c +++ /dev/null @@ -1,133 +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. - */ - -#if defined(__TIZENRT__) - -#include -#include -#include -#include - -#include "modules/iotjs_module_pwm.h" - -static bool iotjs_pwm_set_options(iotjs_pwm_t* pwm) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_t, pwm); - - iotbus_pwm_context_h ctx = _this->ctx; - if (ctx == NULL) { - DDLOG("%s - file open failed", __func__); - return false; - } - - DDDLOG("%s - period: %d, duty: %d", __func__, (int)_this->period, - (int)(_this->duty_cycle * 100)); - - return iotjs_pwm_set_dutycycle(pwm) && iotjs_pwm_set_period(pwm); -} - -void iotjs_pwm_open_worker(uv_work_t* work_req) { - PWM_WORKER_INIT; - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_t, pwm); - - _this->ctx = iotbus_pwm_open(0, (int)_this->pin); - if (_this->ctx == NULL) { - DDLOG("%s - file open failed", __func__); - req_data->result = false; - return; - } - - if (!iotjs_pwm_set_options(pwm)) { - req_data->result = false; - return; - } - - req_data->result = true; -} - -bool iotjs_pwm_set_period(iotjs_pwm_t* pwm) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_t, pwm); - - iotbus_pwm_context_h ctx = _this->ctx; - if (ctx == NULL) { - DDLOG("%s - file open failed", __func__); - return false; - } - - uint32_t period_us = (uint32_t)(1000000 * _this->period); - - return iotbus_pwm_set_period(ctx, period_us) == 0; -} - - -bool iotjs_pwm_set_dutycycle(iotjs_pwm_t* pwm) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_t, pwm); - - iotbus_pwm_context_h ctx = _this->ctx; - if (ctx == NULL) { - DDLOG("%s - file open failed", __func__); - return false; - } - - uint32_t duty_cycle_per_cent = (uint32_t)(_this->duty_cycle * 100); - - return iotbus_pwm_set_duty_cycle(ctx, duty_cycle_per_cent) == 0; -} - - -bool iotjs_pwm_set_enable(iotjs_pwm_t* pwm) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_t, pwm); - - iotbus_pwm_context_h ctx = _this->ctx; - if (ctx == NULL) { - DDLOG("%s - file open failed", __func__); - return false; - } - - DDDLOG("%s - enable: %d", __func__, _this->enable); - - int ret; - if (_this->enable) { - ret = iotbus_pwm_set_enabled(ctx, IOTBUS_PWM_ENABLE); - } else { - ret = iotbus_pwm_set_enabled(ctx, IOTBUS_PWM_DISABLE); - } - - if (ret < 0) { - DDLOG("%s - setEnable failed", __func__); - return false; - } - - return true; -} - -bool iotjs_pwm_close(iotjs_pwm_t* pwm) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_pwm_t, pwm); - - iotbus_pwm_context_h ctx = _this->ctx; - if (ctx == NULL) { - DDLOG("%s - file not opened", __func__); - return false; - } - - DDDLOG("%s", __func__); - - iotbus_pwm_close(ctx); - _this->ctx = NULL; - - return true; -} - - -#endif // __TIZENRT__ diff --git a/src/platform/tizenrt/iotjs_module_uart-tizenrt.c b/src/platform/tizenrt/iotjs_module_uart-tizenrt.c deleted file mode 100644 index bc2b9ed2b4..0000000000 --- a/src/platform/tizenrt/iotjs_module_uart-tizenrt.c +++ /dev/null @@ -1,77 +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. - */ - -#if defined(__TIZENRT__) - - -#include "modules/iotjs_module_uart.h" - -void iotjs_uart_open_worker(uv_work_t* work_req) { - UART_WORKER_INIT; - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_uart_t, uart); - - int fd = open(iotjs_string_data(&_this->device_path), - O_RDWR | O_NOCTTY | O_NDELAY); - - if (fd < 0) { - req_data->result = false; - return; - } - - _this->device_fd = fd; - uv_poll_t* poll_handle = &_this->poll_handle; - - uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get()); - uv_poll_init(loop, poll_handle, fd); - poll_handle->data = uart; - uv_poll_start(poll_handle, UV_READABLE, iotjs_uart_read_cb); - - req_data->result = true; -} - - -bool iotjs_uart_write(iotjs_uart_t* uart) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_uart_t, uart); - int bytesWritten = 0; - unsigned offset = 0; - int fd = _this->device_fd; - const char* buf_data = iotjs_string_data(&_this->buf_data); - - DDDLOG("%s - data: %s", __func__, buf_data); - - do { - errno = 0; - bytesWritten = write(fd, buf_data + offset, _this->buf_len - offset); - - DDDLOG("%s - size: %d", __func__, _this->buf_len - offset); - - if (bytesWritten != -1) { - offset += (unsigned)bytesWritten; - continue; - } - - if (errno == EINTR) { - continue; - } - - return false; - - } while (_this->buf_len > offset); - - return true; -} - - -#endif // __TIZENRT__ diff --git a/test/external_modules/mymodule1/js/helloworld.js b/test/external_modules/mymodule1/js/helloworld.js new file mode 100644 index 0000000000..a4e43834e0 --- /dev/null +++ b/test/external_modules/mymodule1/js/helloworld.js @@ -0,0 +1,19 @@ +/* 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. + */ + +module.exports = { + foo: function() { return "Hello"; }, + message: " world!" +} diff --git a/test/external_modules/mymodule1/modules.json b/test/external_modules/mymodule1/modules.json new file mode 100644 index 0000000000..57f87da95e --- /dev/null +++ b/test/external_modules/mymodule1/modules.json @@ -0,0 +1,8 @@ +{ + "modules": { + "mymodule1": { + "js_file": "js/helloworld.js", + "require": ["buffer", "console"] + } + } +} diff --git a/test/external_modules/mymodule2/modules.json b/test/external_modules/mymodule2/modules.json new file mode 100644 index 0000000000..0dbdd37752 --- /dev/null +++ b/test/external_modules/mymodule2/modules.json @@ -0,0 +1,9 @@ +{ + "modules": { + "mymodule2": { + "native_files": ["my_module.c"], + "init": "InitMyNativeModule" + } + } +} + diff --git a/samples/systemio_pin.js b/test/external_modules/mymodule2/my_module.c similarity index 71% rename from samples/systemio_pin.js rename to test/external_modules/mymodule2/my_module.c index c4ec6e68ff..ba70252c7f 100644 --- a/samples/systemio_pin.js +++ b/test/external_modules/mymodule2/my_module.c @@ -13,15 +13,10 @@ * limitations under the License. */ -var pin = {}; +#include "iotjs_def.h" -if (process.platform === 'linux') { - pin.led1 = 20; -} else if (process.platform === 'nuttx') { - var stm32_pin = require('stm32f4dis').pin; - pin.led1 = stm32_pin.PA10; -} else { - throw new Error('Unsupported platform'); +jerry_value_t InitMyNativeModule() { + jerry_value_t mymodule = jerry_create_object(); + iotjs_jval_set_property_string_raw(mymodule, "message", "Hello world!"); + return mymodule; } - -exports.pin = pin; diff --git a/samples/net_hello/server.js b/test/external_modules/test-external-module1.js similarity index 78% rename from samples/net_hello/server.js rename to test/external_modules/test-external-module1.js index fc5df42a35..3564974dd3 100644 --- a/samples/net_hello/server.js +++ b/test/external_modules/test-external-module1.js @@ -13,13 +13,7 @@ * limitations under the License. */ -var net = require('net'); +var assert = require('assert'); +var mymodule = require('mymodule1'); -var port = 7468; -var server = net.createServer(); - -server.listen(port, 5); - -server.on('connection', function(socket) { - socket.end('Hello IoT.js'); -}); +assert.equal(mymodule.foo() + mymodule.message, "Hello world!"); diff --git a/test/external_modules/test-external-module2.js b/test/external_modules/test-external-module2.js new file mode 100644 index 0000000000..0911d7d2d3 --- /dev/null +++ b/test/external_modules/test-external-module2.js @@ -0,0 +1,19 @@ +/* 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 mymodule = require('mymodule2'); + +assert.equal(mymodule.message, "Hello world!"); diff --git a/src/js/stm32f4dis.js b/test/hello.js similarity index 82% rename from src/js/stm32f4dis.js rename to test/hello.js index 2cbcb06069..f79ce5014c 100644 --- a/src/js/stm32f4dis.js +++ b/test/hello.js @@ -1,4 +1,4 @@ -/* Copyright 2016-present Samsung Electronics Co., Ltd. and other contributors +/* Copyright 2019-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. @@ -13,4 +13,4 @@ * limitations under the License. */ -module.exports = process.binding(process.binding.stm32f4dis); +console.log("Hello IoT.js!"); diff --git a/test/module_generator/test.py b/test/module_generator/test.py new file mode 100755 index 0000000000..e94bcc060a --- /dev/null +++ b/test/module_generator/test.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python + +# Copyright 2019-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. + +import sys +import os + +sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'tools')) +from common_py import path +from common_py.system.executor import Executor as ex +from common_py.system.filesystem import FileSystem as fs + +module_generator_dir = fs.join(path.TOOLS_ROOT, 'module_generator') +generator_script = fs.join(path.TOOLS_ROOT, 'iotjs-generate-module.py') +build_script = fs.join(path.TOOLS_ROOT, 'build.py') + +def print_green(msg): + print ('\033[1;32m{}\033[00m'.format(msg)) + +def print_blue(msg): + print ('\033[1;34m{}\033[00m'.format(msg)) + +def test_c(): + test_dir = fs.join(os.path.dirname(__file__), 'test_c') + test_c = fs.join(test_dir, 'test.c') + + # Compile test.c and make a static library + print_blue('Compile C test module.') + ex.check_run_cmd_output('cc', ['-c', test_c, '-o', test_dir + '/test.o']) + ex.check_run_cmd_output('ar', ['-cr', test_dir + '/libtest.a', + test_dir + '/test.o']) + + # Generate test_module + print_blue('Generate binding for C test module.') + ex.check_run_cmd_output(generator_script, [test_dir, 'c']) + + # Build iotjs + print_blue('Build IoT.js.') + module_dir = fs.join(module_generator_dir, 'output', 'test_c_module') + args = [ + '--external-module=' + module_dir, + '--cmake-param=-DENABLE_MODULE_TEST_C_MODULE=ON', + '--jerry-profile=es2015-subset', + '--clean' + ] + ex.check_run_cmd_output(build_script, args) + + run_test_js(test_dir) + + print_green('C test succeeded.') + +def test_cpp(): + test_dir = fs.join(os.path.dirname(__file__), 'test_cpp') + test_cpp = fs.join(test_dir, 'test.cpp') + + # Compile test.c and make a static library + print_blue('Compile C++ test module.') + ex.check_run_cmd_output('c++', ['-c', test_cpp, '-o', test_dir + '/test.o']) + ex.check_run_cmd_output('ar', ['-cr', test_dir + '/libtest.a', + test_dir + '/test.o']) + + # Generate test_module + print_blue('Generate binding for C++ test module.') + ex.check_run_cmd_output(generator_script, [test_dir, 'c++']) + + # Build iotjs + print_blue('Build IoT.js.') + module_dir = fs.join(module_generator_dir, 'output', 'test_cpp_module') + args = [ + '--external-module=' + module_dir, + '--cmake-param=-DENABLE_MODULE_TEST_CPP_MODULE=ON', + '--jerry-profile=es2015-subset', + '--clean' + ] + ex.check_run_cmd_output(build_script, args) + + run_test_js(test_dir) + + print_green('C++ test succeeded.') + +def run_test_js(test_dir): + # Run test.js + print_blue('Run test.js file.') + binary = fs.join(path.BUILD_ROOT, 'x86_64-linux', 'debug', 'bin', 'iotjs') + test_js = fs.join(test_dir, 'test.js') + ex.check_run_cmd_output(binary, [test_js]) + + +if __name__ == '__main__': + import argparse + + parser = argparse.ArgumentParser() + parser.add_argument('-x', choices=['c', 'c++'], action='append', + default=[], help='Specify language.') + args = parser.parse_args() + + if not args.x: + test_c() + test_cpp() + if 'c' in args.x: + test_c() + if 'c++' in args.x: + test_cpp() diff --git a/test/module_generator/test_c/test.c b/test/module_generator/test_c/test.c new file mode 100644 index 0000000000..040087068c --- /dev/null +++ b/test/module_generator/test_c/test.c @@ -0,0 +1,91 @@ +/* Copyright 2019-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 "test.h" + +void f_void(void) { + return; +} + +int f_int(int a) { + return a; +} + +char f_char(char a) { + return a; +} + +e f_enum(e a) { + return a; +} + +float f_float(float a) { + return a; +} + +double f_double(double a) { + return a; +} + +_Bool f_bool(_Bool a) { + return a; +} + +S f_struct(S a) { + return a; +} + +U f_union(U a) { + return a; +} + +char* f_char_ptr(char* a) { + return a; +} + +char* f_char_arr(char a[5]) { + return a; +} + +int* f_int_ptr(int* a) { + return a; +} + +int* f_int_arr(int a[5]) { + return a; +} + +int f_func(func f) { + if (f) { + return f(); + } + return 0; +} + +int f_func_ptr(func_ptr f) { + if (f) { + return f(); + } + return 0; +} + +void f_struct_ptr(S* s) { + s->c = 's'; + s->i = 42; +} + +void f_union_ptr(U* u) { + u->i = 65; +} diff --git a/test/module_generator/test_c/test.h b/test/module_generator/test_c/test.h new file mode 100644 index 0000000000..dc4373a22e --- /dev/null +++ b/test/module_generator/test_c/test.h @@ -0,0 +1,88 @@ +/* Copyright 2019-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 TEST_H +#define TEST_H + +#define BIN 0b101 +#define DEC 42 +#define OCT 017 +#define HEX 0xFF +#define one_l 1l +#define one_L 1L +#define one_u 1u +#define one_U 1U +#define SIGNED -42 +#define FLOAT 1.5 +#define SFLOAT -1.5 +#define PI 314159E-5 +#define CH 'a' +#define STRING "AaBb" +#define ONE 1 +#define TWO ONE + 1 +#define THREE (ONE) | (TWO) + +char c; +int i; +typedef enum { A, B = 10 } e; +float f; +double d; +_Bool b; +char* c_ptr; +char c_arr[5]; +int* i_ptr; +int i_arr[5]; + +typedef struct { + int i; + char c; +} S; + +typedef struct { const int i; } const_S; + +typedef union { + int i; + char c; +} U; + +typedef union { const int i; } const_U; + +S s; +const_S const_s; +U u; +const_U const_u; + +typedef int(func)(void); +typedef int (*func_ptr)(void); + +void f_void(void); +int f_int(int); +char f_char(char); +e f_enum(e); +float f_float(float); +double f_double(double); +_Bool f_bool(_Bool); +S f_struct(S); +U f_union(U); +char* f_char_ptr(char*); +char* f_char_arr(char[5]); +int* f_int_ptr(int*); +int* f_int_arr(int[5]); +int f_func(func); +int f_func_ptr(func_ptr); +void f_struct_ptr(S*); +void f_union_ptr(U*); + +#endif diff --git a/test/module_generator/test_c/test.js b/test/module_generator/test_c/test.js new file mode 100644 index 0000000000..497e2591b4 --- /dev/null +++ b/test/module_generator/test_c/test.js @@ -0,0 +1,215 @@ +/* Copyright 2019-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 lib = require("test_c_module"); + +// MACROS +assert.equal(lib.BIN, 5); +assert.equal(lib.DEC, 42); +assert.equal(lib.OCT, 15); +assert.equal(lib.HEX, 255); +assert.equal(lib.one_l, 1); +assert.equal(lib.one_L, 1); +assert.equal(lib.one_u, 1); +assert.equal(lib.one_U, 1); +assert.equal(lib.SIGNED, -42); +assert.equal(lib.FLOAT, 1.5); +assert.equal(lib.SFLOAT, -1.5); +assert.equal(lib.PI, 3.14159); +assert.equal(lib.CH, 'a'); +assert.equal(lib.STRING, 'AaBb'); +assert.equal(lib.ONE, 1); +assert.equal(lib.TWO, 2); +assert.equal(lib.THREE, 3); + +// VARIABLES +assert.equal(lib.c, '\u0000'); +assert.equal(lib.i, 0); +assert.equal(lib.A, 0); +assert.equal(lib.B, 10); +assert.equal(lib.f, 0); +assert.equal(lib.d, 0); +assert.equal(lib.b, false); +assert.equal(lib.c_ptr, null); +assert.equal(lib.c_arr, ''); +assert.equal(lib.i_ptr, null); +assert.equal(lib.i_arr.length, 5); +for (var i = 0; i < 5; i++) { + assert.equal(lib.i_arr[i], 0); +} + +assert.equal(lib.s.i, 0); +assert.equal(lib.s.c, '\u0000'); +assert.equal(lib.u.i, 0); +assert.equal(lib.u.c, '\u0000'); + +lib.c = 'Z'; +assert.equal(lib.c, 'Z'); + +lib.i = 42; +assert.equal(lib.i, 42); + +lib.A = 1; +lib.B = 2; +assert.equal(lib.A, 0); +assert.equal(lib.B, 10); + +lib.f = 1.5; +assert.equal(lib.f, 1.5); + +lib.d = 2.5; +assert.equal(lib.d, 2.5); + +lib.b = undefined; +assert(!lib.b); +lib.b = null; +assert(!lib.b); +lib.b = true; +assert(lib.b); +lib.b = 0; +assert(!lib.b); +lib.b = 1; +assert(lib.b); +lib.b = ''; +assert(!lib.b); +lib.b = 't'; +assert(lib.b); +lib.b = {}; +assert(lib.b); + +lib.c_ptr = 'abcdefghijklmnopqrstuvwxyz'; +assert.equal(lib.c_ptr, 'abcdefghijklmnopqrstuvwxyz'); +lib.c_ptr = ''; +assert.equal(lib.c_ptr, ''); + +lib.c_arr = 'a'; +assert.equal(lib.c_arr, 'a'); +lib.c_arr = 'ab'; +assert.equal(lib.c_arr, 'ab'); +lib.c_arr = 'abc'; +assert.equal(lib.c_arr, 'abc'); +lib.c_arr = 'abcd'; +assert.equal(lib.c_arr, 'abcd'); +lib.c_arr = 'abcde'; +assert.equal(lib.c_arr, 'abcd'); + +var i_ptr = new Int32Array(new ArrayBuffer(4), 0, 1); +i_ptr[0] = 42; +lib.i_ptr = i_ptr; +assert.equal(lib.i_ptr[0], 42); +assert.equal(lib.i_ptr[0], i_ptr[0]); +assert(lib.i_ptr instanceof Int32Array); +lib.i_ptr = null; +assert.equal(lib.i_ptr, null); + +assert(lib.i_arr instanceof Int32Array); +for (var i = 0; i < 5; i++) { + lib.i_arr[i] = i*i; +} +for (var i = 0; i < 5; i++) { + assert.equal(lib.i_arr[i], i*i); +} +lib.i_arr = null; +assert(lib.i_arr instanceof Int32Array); + +var s = new lib.S(); +s.i = 42; +s.c = 's'; +lib.s = s; +assert.equal(lib.s.i, 42); +assert.equal(lib.s.c, 's'); +lib.s.i = 100; +lib.s.c = 'c'; +assert.equal(lib.s.i, 100); +assert.equal(lib.s.c, 'c'); + +var c_s = new lib.const_S(); +assert.equal(c_s.i, 0); +c_s.i = 42; +assert.equal(c_s.i, 0); +c_s = new lib.const_S({ + i : 42 +}); +assert.equal(c_s.i, 42); +c_s.i = 0; +assert.equal(c_s.i, 42); +assert.equal(lib.const_s.i, 0); +lib.const_s.i = 42; +assert.equal(lib.const_s.i, 0); + +var u = new lib.U(); +u.i = 65; +lib.u = u; +assert.equal(lib.u.i, 65); +assert.equal(lib.u.c, 'A'); +lib.u.i = 66; +assert.equal(lib.u.c, 'B'); + +var c_u = new lib.const_U(); +assert.equal(c_u.i, 0); +c_u.i = 42; +assert.equal(c_u.i, 0); +c_u = new lib.const_U({ + i : 42 +}); +assert.equal(c_u.i, 42); +c_u.i = 0; +assert.equal(c_u.i, 42); +assert.equal(lib.const_u.i, 0); +lib.const_u.i = 42; +assert.equal(lib.const_u.i, 0); + +// FUNCTIONS +assert.equal(lib.f_void(), undefined); +assert.equal(lib.f_int(5), 5); +assert.equal(lib.f_char('a'), 'a'); +assert.equal(lib.f_enum(lib.A), 0); +assert.equal(lib.f_float(1.5), 1.5); +assert.equal(lib.f_double(2.5), 2.5); +assert.equal(lib.f_bool(true), true); +assert.equal(lib.f_struct(s).i, 42); +assert.equal(lib.f_struct(s).c, 's'); +assert.equal(lib.f_union(u).i, 65); +assert.equal(lib.f_union(u).c, 'A'); +assert.equal(lib.f_char_ptr(null), null); +assert.equal(lib.f_char_ptr('string'), 'string'); +assert.equal(lib.f_char_arr(null), null); +assert.equal(lib.f_char_arr('string'), 'string'); +assert.equal(lib.f_int_ptr(null), null); +assert.equal(lib.f_int_ptr(i_ptr)[0], 42); +assert.equal(lib.f_int_arr(null), null); +assert.equal(lib.f_int_arr(i_ptr)[0], 42); +assert.equal(lib.f_func(null), 0); +assert.equal(lib.f_func(function () { + return 42; +}), 42); +assert.equal(lib.f_func_ptr(null), 0); +assert.equal(lib.f_func_ptr(function () { + return 42; +}), 42); +s.c = '\u0000'; +s.i = 0; +assert.equal(s.c, '\u0000'); +assert.equal(s.i, 0); +lib.f_struct_ptr(s); +assert.equal(s.c, 's'); +assert.equal(s.i, 42); +u.i = 0; +assert.equal(u.c, '\u0000'); +assert.equal(u.i, 0); +lib.f_union_ptr(u); +assert.equal(u.c, 'A'); +assert.equal(u.i, 65); diff --git a/test/module_generator/test_cpp/test.cpp b/test/module_generator/test_cpp/test.cpp new file mode 100644 index 0000000000..e6b65ba217 --- /dev/null +++ b/test/module_generator/test_cpp/test.cpp @@ -0,0 +1,278 @@ +/* Copyright 2019-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 "test.h" + +char c; +int i; +float f; +double d; +bool b; +char* c_ptr; +char c_arr[5]; +int* i_ptr; +int i_arr[5]; + +S s; +const_S const_s = {0}; +U u; +const_U const_u = {0}; + +void f_void (void) +{ + return; +} + +int f_int (int a) +{ + return a; +} + +char f_char (char a) +{ + return a; +} + +e f_enum (e a) +{ + return a; +} + +float f_float (float a) +{ + return a; +} + +double f_double (double a) +{ + return a; +} + +bool f_bool (bool a) +{ + return a; +} + +S f_struct (S a) +{ + return a; +} + +U f_union (U a) +{ + return a; +} + +char* f_char_ptr (char* a) +{ + return a; +} + +char* f_char_arr (char a[5]) +{ + return a; +} + +int* f_int_ptr (int* a) +{ + return a; +} + +int* f_int_arr (int a[5]) +{ + return a; +} + +int f_func (func f) +{ + if (f) + { + return f(); + } + return 0; +} + +int f_func_ptr (func_ptr f) +{ + if (f) + { + return f(); + } + return 0; +} + +void f_struct_ptr(S* s) { + s->c = 's'; + s->i = 42; +} + +void f_union_ptr(U* u) { + u->i = 65; +} + +char Test::get_c() +{ + return _c; +} + +void Test::set_c(char c) +{ + _c = c; +} + +int Test::get_i() +{ + return _i; +} + +void Test::set_i(int i) +{ + _i = i; +} + +float Test::get_f() +{ + return _f; +} + +void Test::set_f(float f) +{ + _f = f; +} + +double Test::get_d() +{ + return _d; +} + +void Test::set_d(double d) +{ + _d = d; +} + +bool Test::get_b() +{ + return _b; +} + +void Test::set_b(bool b) +{ + _b = b; +} + +char* Test::get_c_ptr() +{ + return _c_ptr; +} + +void Test::set_c_ptr(char* c_ptr, int size) +{ + if (_c_ptr) + { + delete _c_ptr; + } + _c_ptr = new char[sizeof(char) * size + 1]; + for (int i = 0; i < size; i++) + { + _c_ptr[i] = c_ptr[i]; + } + _c_ptr[size] = '\0'; +} + +char* Test::get_c_arr() +{ + return _c_arr; +} + +void Test::set_c_arr(char c_arr[5]) +{ + for (int i = 0; i < 4; i++) + { + _c_arr[i] = c_arr[i]; + } +} + +int* Test::get_i_ptr() +{ + return _i_ptr; +} + +void Test::set_i_ptr(int* i_ptr, int size) +{ + if (_i_ptr) + { + delete _i_ptr; + } + _i_ptr = new int[sizeof(int) * size]; + for (int i = 0; i < size; i++) + { + _i_ptr[i] = i_ptr[i]; + } +} + +int* Test::get_i_arr() +{ + return _i_arr; +} + +void Test::set_i_arr(int i_arr[5]) +{ + for (int i = 0; i < 5; i++) + { + _i_arr[i] = i_arr[i]; + } +} + +S Test::get_s() +{ + return _s; +} + +void Test::set_s(S s) +{ + _s.i = s.i; + _s.c = s.c; +} + +U Test::get_u() +{ + return _u; +} + +void Test::set_u(U u) +{ + _u.i = u.i; + _u.c = u.c; +} + +O Test::get_o() +{ + return _o; +} + +void Test::set_o(O o) +{ + _o = o; +} + +int test_ns::A::foo() +{ + return 1; +} + +int test_ns::nested_ns::A::foo() +{ + return 2; +} diff --git a/test/module_generator/test_cpp/test.h b/test/module_generator/test_cpp/test.h new file mode 100644 index 0000000000..bce1d04af8 --- /dev/null +++ b/test/module_generator/test_cpp/test.h @@ -0,0 +1,166 @@ +/* Copyright 2019-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. + */ + +#pragma once + +#define BIN 0b101 +#define DEC 42 +#define OCT 017 +#define HEX 0xFF +#define one_l 1l +#define one_L 1L +#define one_u 1u +#define one_U 1U +#define SIGNED -42 +#define FLOAT 1.5 +#define SFLOAT -1.5 +#define PI 314159E-5 +#define CH 'a' +#define STRING "AaBb" +#define ONE 1 +#define TWO ONE + 1 +#define THREE (ONE) | (TWO) + +extern char c; +extern int i; +typedef enum { A, B = 10 } e; +extern float f; +extern double d; +extern bool b; +extern char* c_ptr; +extern char c_arr[5]; +extern int* i_ptr; +extern int i_arr[5]; + +typedef struct { + int i; + char c; +} S; + +typedef struct { const int i; } const_S; + +typedef union { + int i; + char c; +} U; + +typedef union { const int i; } const_U; + +extern S s; +extern const_S const_s; +extern U u; +extern const_U const_u; + +typedef int(func)(void); +typedef int (*func_ptr)(void); + +void f_void(void); +int f_int(int); +char f_char(char); +e f_enum(e); +float f_float(float); +double f_double(double); +bool f_bool(bool); +S f_struct(S); +U f_union(U); +char* f_char_ptr(char*); +char* f_char_arr(char[5]); +int* f_int_ptr(int*); +int* f_int_arr(int[5]); +int f_func(func); +int f_func_ptr(func_ptr); +void f_struct_ptr(S*); +void f_union_ptr(U*); + +class O { + int _i; + + public: + O() : _i(42) { + } + int get_i() { + return _i; + } + void set_i(int i) { + _i = i; + } +}; + +class Test { + char _c; + int _i; + float _f; + double _d; + bool _b; + char* _c_ptr; + char _c_arr[5]; + int* _i_ptr; + int _i_arr[5]; + S _s; + U _u; + O _o; + + public: + char c; + int i; + float f; + double d; + bool b; + char* c_ptr; + char c_arr[5]; + int* i_ptr; + int i_arr[5]; + S s; + U u; + O o; + + char get_c(); + void set_c(char); + int get_i(); + void set_i(int); + float get_f(); + void set_f(float); + double get_d(); + void set_d(double); + bool get_b(); + void set_b(bool); + char* get_c_ptr(); + void set_c_ptr(char*, int); + char* get_c_arr(); + void set_c_arr(char[5]); + int* get_i_ptr(); + void set_i_ptr(int*, int); + int* get_i_arr(); + void set_i_arr(int[5]); + S get_s(); + void set_s(S); + U get_u(); + void set_u(U); + O get_o(); + void set_o(O); +}; + +namespace test_ns { +namespace nested_ns { +class A { + public: + int foo(); +}; +} +class A { + public: + int foo(); +}; +} diff --git a/test/module_generator/test_cpp/test.js b/test/module_generator/test_cpp/test.js new file mode 100644 index 0000000000..e027559c43 --- /dev/null +++ b/test/module_generator/test_cpp/test.js @@ -0,0 +1,360 @@ +/* Copyright 2019-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 lib = require("test_cpp_module"); + +// MACROS +assert.equal(lib.BIN, 5); +assert.equal(lib.DEC, 42); +assert.equal(lib.OCT, 15); +assert.equal(lib.HEX, 255); +assert.equal(lib.one_l, 1); +assert.equal(lib.one_L, 1); +assert.equal(lib.one_u, 1); +assert.equal(lib.one_U, 1); +assert.equal(lib.SIGNED, -42); +assert.equal(lib.FLOAT, 1.5); +assert.equal(lib.SFLOAT, -1.5); +assert.equal(lib.PI, 3.14159); +assert.equal(lib.CH, 'a'); +assert.equal(lib.STRING, 'AaBb'); +assert.equal(lib.ONE, 1); +assert.equal(lib.TWO, 2); +assert.equal(lib.THREE, 3); + +// VARIABLES +assert.equal(lib.c, '\u0000'); +assert.equal(lib.i, 0); +assert.equal(lib.A, 0); +assert.equal(lib.B, 10); +assert.equal(lib.f, 0); +assert.equal(lib.d, 0); +assert.equal(lib.b, false); +assert.equal(lib.c_ptr, null); +assert.equal(lib.c_arr, ''); +assert.equal(lib.i_ptr, null); +assert.equal(lib.i_arr.length, 5); +for (var i = 0; i < 5; i++) { + assert.equal(lib.i_arr[i], 0); +} + +assert.equal(lib.s.i, 0); +assert.equal(lib.s.c, '\u0000'); +assert.equal(lib.u.i, 0); +assert.equal(lib.u.c, '\u0000'); + +lib.c = 'Z'; +assert.equal(lib.c, 'Z'); + +lib.i = 42; +assert.equal(lib.i, 42); + +lib.A = 1; +lib.B = 2; +assert.equal(lib.A, 0); +assert.equal(lib.B, 10); + +lib.f = 1.5; +assert.equal(lib.f, 1.5); + +lib.d = 2.5; +assert.equal(lib.d, 2.5); + +lib.b = undefined; +assert(!lib.b); +lib.b = null; +assert(!lib.b); +lib.b = true; +assert(lib.b); +lib.b = 0; +assert(!lib.b); +lib.b = 1; +assert(lib.b); +lib.b = ''; +assert(!lib.b); +lib.b = 't'; +assert(lib.b); +lib.b = {}; +assert(lib.b); + +lib.c_ptr = 'abcdefghijklmnopqrstuvwxyz'; +assert.equal(lib.c_ptr, 'abcdefghijklmnopqrstuvwxyz'); +lib.c_ptr = ''; +assert.equal(lib.c_ptr, ''); + +lib.c_arr = 'a'; +assert.equal(lib.c_arr, 'a'); +lib.c_arr = 'ab'; +assert.equal(lib.c_arr, 'ab'); +lib.c_arr = 'abc'; +assert.equal(lib.c_arr, 'abc'); +lib.c_arr = 'abcd'; +assert.equal(lib.c_arr, 'abcd'); +lib.c_arr = 'abcde'; +assert.equal(lib.c_arr, 'abcd'); + +var i_ptr = new Int32Array(new ArrayBuffer(4), 0, 1); +i_ptr[0] = 42; +lib.i_ptr = i_ptr; +assert.equal(lib.i_ptr[0], 42); +assert.equal(lib.i_ptr[0], i_ptr[0]); +assert(lib.i_ptr instanceof Int32Array); +lib.i_ptr = null; +assert.equal(lib.i_ptr, null); + +assert(lib.i_arr instanceof Int32Array); +for (var i = 0; i < 5; i++) { + lib.i_arr[i] = i*i; +} +for (var i = 0; i < 5; i++) { + assert.equal(lib.i_arr[i], i*i); +} +lib.i_arr = null; +assert(lib.i_arr instanceof Int32Array); + +var s = new lib.S(); +s.i = 42; +s.c = 's'; +lib.s = s; +assert.equal(lib.s.i, 42); +assert.equal(lib.s.c, 's'); +lib.s.i = 100; +lib.s.c = 'c'; +assert.equal(lib.s.i, 100); +assert.equal(lib.s.c, 'c'); + +var c_s = new lib.const_S(); +assert.equal(c_s.i, 0); +c_s.i = 42; +assert.equal(c_s.i, 0); +c_s = new lib.const_S({ + i : 42 +}); +assert.equal(c_s.i, 42); +c_s.i = 0; +assert.equal(c_s.i, 42); +assert.equal(lib.const_s.i, 0); +lib.const_s.i = 42; +assert.equal(lib.const_s.i, 0); + +var u = new lib.U(); +u.i = 65; +lib.u = u; +assert.equal(lib.u.i, 65); +assert.equal(lib.u.c, 'A'); +lib.u.i = 66; +assert.equal(lib.u.c, 'B'); + +var c_u = new lib.const_U(); +assert.equal(c_u.i, 0); +c_u.i = 42; +assert.equal(c_u.i, 0); +c_u = new lib.const_U({ + i : 42 +}); +assert.equal(c_u.i, 42); +c_u.i = 0; +assert.equal(c_u.i, 42); +assert.equal(lib.const_u.i, 0); +lib.const_u.i = 42; +assert.equal(lib.const_u.i, 0); + +// FUNCTIONS +assert.equal(lib.f_void(), undefined); +assert.equal(lib.f_int(5), 5); +assert.equal(lib.f_char('a'), 'a'); +assert.equal(lib.f_enum(lib.A), 0); +assert.equal(lib.f_float(1.5), 1.5); +assert.equal(lib.f_double(2.5), 2.5); +assert.equal(lib.f_bool(true), true); +assert.equal(lib.f_struct(s).i, 42); +assert.equal(lib.f_struct(s).c, 's'); +assert.equal(lib.f_union(u).i, 65); +assert.equal(lib.f_union(u).c, 'A'); +assert.equal(lib.f_char_ptr(null), null); +assert.equal(lib.f_char_ptr('string'), 'string'); +assert.equal(lib.f_char_arr(null), null); +assert.equal(lib.f_char_arr('string'), 'string'); +assert.equal(lib.f_int_ptr(null), null); +assert.equal(lib.f_int_ptr(i_ptr)[0], 42); +assert.equal(lib.f_int_arr(null), null); +assert.equal(lib.f_int_arr(i_ptr)[0], 42); +assert.equal(lib.f_func(null), 0); +assert.equal(lib.f_func(function () { + return 42; +}), 42); +assert.equal(lib.f_func_ptr(null), 0); +assert.equal(lib.f_func_ptr(function () { + return 42; +}), 42); +s.c = '\u0000'; +s.i = 0; +assert.equal(s.c, '\u0000'); +assert.equal(s.i, 0); +lib.f_struct_ptr(s); +assert.equal(s.c, 's'); +assert.equal(s.i, 42); +u.i = 0; +assert.equal(u.c, '\u0000'); +assert.equal(u.i, 0); +lib.f_union_ptr(u); +assert.equal(u.c, 'A'); +assert.equal(u.i, 65); + +// CLASS +test = new lib.Test(); + +// public members +assert.equal(test.c, '\u0000'); +assert.equal(test.i, 0); +assert.equal(test.f, 0); +assert.equal(test.d, 0); +assert.equal(test.b, false); +assert.equal(test.c_ptr, null); +assert.equal(test.c_arr, ''); +assert.equal(test.i_ptr, null); +assert.equal(test.i_arr.length, 5); +for (var i = 0; i < 5; i++) { + assert.equal(test.i_arr[i], 0); +} +// char +test.c = 'Z'; +assert.equal(test.c, 'Z'); +// int +test.i = 42; +assert.equal(test.i, 42); +// float +test.f = 1.5; +assert.equal(test.f, 1.5); +// double +test.d = 2.5; +assert.equal(test.d, 2.5); +// bool +test.b = true; +assert(test.b); +// char* +test.c_ptr = 'abcdefghijklmnopqrstuvwxyz'; +assert.equal(test.c_ptr, 'abcdefghijklmnopqrstuvwxyz'); +test.c_ptr = ''; +assert.equal(test.c_ptr, ''); +// char[] +test.c_arr = 'a'; +assert.equal(test.c_arr, 'a'); +test.c_arr = 'ab'; +assert.equal(test.c_arr, 'ab'); +test.c_arr = 'abc'; +assert.equal(test.c_arr, 'abc'); +test.c_arr = 'abcd'; +assert.equal(test.c_arr, 'abcd'); +test.c_arr = 'abcde'; +assert.equal(test.c_arr, 'abcd'); +// int* +test.i_ptr = i_ptr; +assert.equal(test.i_ptr[0], 42); +assert.equal(test.i_ptr[0], i_ptr[0]); +assert(test.i_ptr instanceof Int32Array); +test.i_ptr = null; +assert.equal(test.i_ptr, null); +// int[] +assert(test.i_arr instanceof Int32Array); +for (var i = 0; i < 5; i++) { + test.i_arr[i] = i*i; +} +for (var i = 0; i < 5; i++) { + assert.equal(test.i_arr[i], i*i); +} +test.i_arr = null; +assert(test.i_arr instanceof Int32Array); +// S struct +test.s = s; +assert.equal(test.s.i, 42); +assert.equal(test.s.c, 's'); +// U union +test.u = u; +assert.equal(test.u.i, 65); +assert.equal(test.u.c, 'A'); +// O class +assert.equal(test.o.get_i(), 42); +var o = new lib.O(); +o.set_i(100); +test.o = o; +assert.equal(test.o.get_i(), 100); +// private members +assert.equal(test.get_c(), '\u0000'); +assert.equal(test.get_i(), 0); +assert.equal(test.get_f(), 0); +assert.equal(test.get_d(), 0); +assert.equal(test.get_b(), false); +assert.equal(test.get_c_ptr(), null); +assert.equal(test.get_c_arr(), ''); +assert.equal(test.get_i_ptr(), null); +assert.equal(test.get_i_arr()[0], 0); +assert(test.get_i_arr() instanceof Int32Array); +// char +test.set_c('Z'); +assert.equal(test.get_c(), 'Z'); +// int +test.set_i(42); +assert.equal(test.get_i(), 42); +// float +test.set_f(1.5); +assert.equal(test.get_f(), 1.5); +// double +test.set_d(2.5); +assert.equal(test.get_d(), 2.5); +// bool +test.set_b(true); +assert(test.get_b()); +// char* +test.set_c_ptr('abcde', 5); +assert.equal(test.get_c_ptr(), 'abcde'); +// char[] +test.set_c_arr('abcd'); +assert.equal(test.get_c_arr(), 'abcd'); +// int* +test.set_i_ptr(i_ptr, 1); +assert.equal(test.get_i_ptr()[0], 42); +// int[] +test.set_i_arr(i_ptr); +assert.equal(test.get_i_arr()[0], 42); +// S struct +test.set_s(s); +assert.equal(test.get_s().i, 42); +assert.equal(test.get_s().c, 's'); +// U union +test.set_u(u); +assert.equal(test.get_u().i, 65); +assert.equal(test.get_u().c, 'A'); +// O class +assert.equal(test.get_o().get_i(), 42); +test.set_o(o); +assert.equal(test.get_o().get_i(), 100); + +// NAMESPACE +test_ns_A = new lib.test_ns.A(); +assert.equal(test_ns_A.foo(), 1); +test_ns_nested_ns_A = new lib.test_ns.nested_ns.A(); +assert.equal(test_ns_nested_ns_A.foo(), 2); + +with (lib.test_ns) { + test_ns_A = new A(); + assert.equal(test_ns_A.foo(), 1); + + with (nested_ns) { + test_ns_nested_ns_A = new A(); + assert.equal(test_ns_nested_ns_A.foo(), 2); + } +} diff --git a/test/napi/.gitignore b/test/napi/.gitignore new file mode 100644 index 0000000000..797585b738 --- /dev/null +++ b/test/napi/.gitignore @@ -0,0 +1,2 @@ +build +*.node diff --git a/test/napi/binding.gyp b/test/napi/binding.gyp new file mode 100644 index 0000000000..741b39073b --- /dev/null +++ b/test/napi/binding.gyp @@ -0,0 +1,88 @@ +{ + "targets": [ + { + "target_name": "test_napi_arguments", + "sources": [ "test_napi_arguments.c" ] + }, + { + "target_name": "test_napi_array", + "sources": [ "test_napi_array.c" ] + }, + { + "target_name": "test_napi_async", + "sources": [ "test_napi_async.c" ] + }, + { + "target_name": "test_napi_buffer", + "sources": [ "test_napi_buffer.c" ] + }, + { + "target_name": "test_napi_construct", + "sources": [ "test_napi_construct.c" ] + }, + { + "target_name": "test_napi_conversions", + "sources": [ "test_napi_conversions.c" ] + }, + { + "target_name": "test_napi_dataview", + "sources": [ "test_napi_dataview.c" ] + }, + { + "target_name": "test_napi_env_compare", + "sources": [ "test_napi_env_compare.c" ] + }, + { + "target_name": "test_napi_env_store", + "sources": [ "test_napi_env_store.c" ] + }, + { + "target_name": "test_napi_error_handling", + "sources": [ "test_napi_error_handling.c" ] + }, + { + "target_name": "test_napi_general", + "sources": [ "test_napi_general.c" ] + }, + { + "target_name": "test_napi_make_callback", + "sources": [ "test_napi_make_callback.c" ] + }, + { + "target_name": "test_napi_object_wrap", + "sources": [ "test_napi_object_wrap.c" ] + }, + { + "target_name": "test_napi_handle_scope", + "sources": [ "test_napi_handle_scope.c" ] + }, + { + "target_name": "test_napi_promise", + "sources": [ "test_napi_promise.c" ] + }, + { + "target_name": "test_napi_properties", + "sources": [ "test_napi_properties.c" ] + }, + { + "target_name": "test_napi_reference", + "sources": [ "test_napi_reference.c" ] + }, + { + "target_name": "test_napi_strictequal_and_instanceof", + "sources": [ "test_napi_strictequal_and_instanceof.c" ] + }, + { + "target_name": "test_napi_string", + "sources": [ "test_napi_string.c" ] + }, + { + "target_name": "test_napi_symbol", + "sources": [ "test_napi_symbol.c" ] + }, + { + "target_name": "test_napi_typedarray", + "sources": [ "test_napi_typedarray.c" ] + } + ] +} diff --git a/test/napi/common.h b/test/napi/common.h new file mode 100644 index 0000000000..046886aa5d --- /dev/null +++ b/test/napi/common.h @@ -0,0 +1,70 @@ +// Empty value so that macros here are able to return NULL or void +#define NAPI_RETVAL_NOTHING // Intentionally blank #define + +#define GET_AND_THROW_LAST_ERROR(env) \ + do { \ + const napi_extended_error_info* error_info; \ + napi_get_last_error_info((env), &error_info); \ + bool is_pending; \ + napi_is_exception_pending((env), &is_pending); \ + /* If an exception is already pending, don't rethrow it */ \ + if (!is_pending) { \ + const char* error_message = error_info->error_message != NULL \ + ? error_info->error_message \ + : "empty error message"; \ + napi_throw_error((env), NULL, error_message); \ + } \ + } while (0) + +#define NAPI_ASSERT_BASE(env, assertion, message, ret_val) \ + do { \ + if (!(assertion)) { \ + napi_throw_error((env), NULL, \ + "assertion (" #assertion ") failed: " message); \ + return ret_val; \ + } \ + } while (0) + +// Returns NULL on failed assertion. +// This is meant to be used inside napi_callback methods. +#define NAPI_ASSERT(env, assertion, message) \ + NAPI_ASSERT_BASE(env, assertion, message, NULL) + +// Returns empty on failed assertion. +// This is meant to be used inside functions with void return type. +#define NAPI_ASSERT_RETURN_VOID(env, assertion, message) \ + NAPI_ASSERT_BASE(env, assertion, message, NAPI_RETVAL_NOTHING) + +#define NAPI_CALL_BASE(env, the_call, ret_val) \ + do { \ + if ((the_call) != napi_ok) { \ + GET_AND_THROW_LAST_ERROR((env)); \ + return ret_val; \ + } \ + } while (0) + +// Returns NULL if the_call doesn't return napi_ok. +#define NAPI_CALL(env, the_call) NAPI_CALL_BASE(env, the_call, NULL) + +// Returns empty if the_call doesn't return napi_ok. +#define NAPI_CALL_RETURN_VOID(env, the_call) \ + NAPI_CALL_BASE(env, the_call, NAPI_RETVAL_NOTHING) + +#define DECLARE_NAPI_PROPERTY(name, func) \ + { (name), 0, (func), 0, 0, 0, napi_default, 0 } + +#define DECLARE_NAPI_GETTER(name, func) \ + { (name), 0, 0, (func), 0, 0, napi_default, 0 } + +#define SET_NAMED_METHOD(env, target, prop_name, handler) \ + do { \ + napi_status status; \ + napi_value fn; \ + status = napi_create_function(env, NULL, 0, handler, NULL, &fn); \ + if (status != napi_ok) \ + return NULL; \ + \ + status = napi_set_named_property(env, target, prop_name, fn); \ + if (status != napi_ok) \ + return NULL; \ + } while (0); diff --git a/test/napi/common.js b/test/napi/common.js new file mode 100644 index 0000000000..d607adef1c --- /dev/null +++ b/test/napi/common.js @@ -0,0 +1,70 @@ +'use strict'; +var assert = require('assert'); +var mustCallChecks = []; + +var buildTypePath = process.debug ? 'Debug' : 'Release'; + +function mustCall(fn, criteria) { + if (typeof fn === 'number') { + criteria = fn; + fn = noop; + } else if (fn === undefined) { + fn = noop; + } + if (criteria === undefined) { + criteria = 1; + } + + if (typeof criteria !== 'number') + throw new TypeError('Invalid value: ' + criteria); + + var context = { + expect: criteria, + actual: 0, + stack: (new Error()).stack, + name: fn.name || '' + }; + + if (mustCallChecks.length === 0) process.on('exit', runCallChecks); + + mustCallChecks.push(context); + + return function() { + ++context.actual; + return fn.apply(this, arguments); + }; +} + +function noop() {} + +function runCallChecks() { + mustCallChecks.forEach(function(it) { + assert.strictEqual( + it.actual, + it.expect, + 'Expect function ' + it.name + ' been called '+ it.expect + ' times, got ' + + it.actual + ' ' + it.stack); + }); +} + +function expectsError(fn, exact) { + // TODO:rigorous assert need! + function innerFn(error) { + return error instanceof Error; + } + + if (fn) { + assert.throws(fn, innerFn, exact); + return; + } + + return mustCall(innerFn, exact); +} + +module.exports = { + mustCall: mustCall, + expectsError: expectsError, + buildTypePath: buildTypePath, + // don't use port in a parallelized test + PORT: process.env.NODE_COMMON_PORT || 12306 +}; diff --git a/test/napi/test_napi_arguments.c b/test/napi/test_napi_arguments.c new file mode 100644 index 0000000000..d8f66ede7a --- /dev/null +++ b/test/napi/test_napi_arguments.c @@ -0,0 +1,37 @@ +#include +#include "common.h" + +static napi_value Throw(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value argv[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); + + NAPI_CALL(env, napi_throw(env, argv[0])); + + return NULL; +} + +static napi_value Return(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value argv[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); + + return argv[0]; +} + +static napi_value ReturnThis(napi_env env, napi_callback_info info) { + napi_value this; + NAPI_CALL(env, napi_get_cb_info(env, info, NULL, NULL, &this, NULL)); + + return this; +} + +static napi_value Init(napi_env env, napi_value exports) { + SET_NAMED_METHOD(env, exports, "Throw", Throw); + SET_NAMED_METHOD(env, exports, "Return", Return); + SET_NAMED_METHOD(env, exports, "ReturnThis", ReturnThis); + + return exports; +} + +NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) diff --git a/test/napi/test_napi_arguments_return.js b/test/napi/test_napi_arguments_return.js new file mode 100644 index 0000000000..166412045e --- /dev/null +++ b/test/napi/test_napi_arguments_return.js @@ -0,0 +1,9 @@ +'use strict'; +var assert = require('assert'); +var common = require('common.js'); +var test = require('./build/' + common.buildTypePath + + '/test_napi_arguments.node'); + + +var obj = {}; +assert.strictEqual(test.Return(obj), obj); diff --git a/test/napi/test_napi_arguments_return_this.js b/test/napi/test_napi_arguments_return_this.js new file mode 100644 index 0000000000..1fc826e28d --- /dev/null +++ b/test/napi/test_napi_arguments_return_this.js @@ -0,0 +1,9 @@ +'use strict'; +var assert = require('assert'); +var common = require('common.js'); +var test = require('./build/' + common.buildTypePath + + '/test_napi_arguments.node'); + + +var obj = {}; +assert.strictEqual(test.ReturnThis.call(obj), obj); diff --git a/test/napi/test_napi_arguments_throw.js b/test/napi/test_napi_arguments_throw.js new file mode 100644 index 0000000000..29259ba9df --- /dev/null +++ b/test/napi/test_napi_arguments_throw.js @@ -0,0 +1,13 @@ +'use strict'; +var assert = require('assert'); +var common = require('common.js'); +var test = require('./build/' + common.buildTypePath + + '/test_napi_arguments.node'); + +try { + test.Throw(new Error('foo')); + assert.fail('fail path'); +} catch (err) { + assert(err != null); + assert.strictEqual(err.message, 'foo'); +} diff --git a/test/napi/test_napi_array.c b/test/napi/test_napi_array.c new file mode 100644 index 0000000000..84740f9407 --- /dev/null +++ b/test/napi/test_napi_array.c @@ -0,0 +1,193 @@ +#include "common.h" +#include "node_api.h" + +#include + +static napi_value TestGetElement(napi_env env, napi_callback_info info) { + size_t argc = 2; + napi_value args[2]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + NAPI_ASSERT(env, argc >= 2, "Wrong number of arguments"); + + napi_valuetype valuetype0; + NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0)); + + NAPI_ASSERT(env, valuetype0 == napi_object, + "Wrong type of arguments. Expects an array as first argument."); + + napi_valuetype valuetype1; + NAPI_CALL(env, napi_typeof(env, args[1], &valuetype1)); + + NAPI_ASSERT( + env, valuetype1 == napi_number, + "Wrong type of arguments. Expects an integer as second argument."); + + napi_value array = args[0]; + int32_t index; + NAPI_CALL(env, napi_get_value_int32(env, args[1], &index)); + + NAPI_ASSERT(env, index >= 0, "Invalid index. Expects a positive integer."); + + bool isarray; + NAPI_CALL(env, napi_is_array(env, array, &isarray)); + + if (!isarray) { + return NULL; + } + + uint32_t length; + NAPI_CALL(env, napi_get_array_length(env, array, &length)); + + NAPI_ASSERT(env, ((uint32_t)index < length), "Index out of bounds!"); + + napi_value ret; + NAPI_CALL(env, napi_get_element(env, array, index, &ret)); + + return ret; +} + +static napi_value TestHasElement(napi_env env, napi_callback_info info) { + size_t argc = 2; + napi_value args[2]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + NAPI_ASSERT(env, argc >= 2, "Wrong number of arguments"); + + napi_valuetype valuetype0; + NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0)); + + NAPI_ASSERT(env, valuetype0 == napi_object, + "Wrong type of arguments. Expects an array as first argument."); + + napi_valuetype valuetype1; + NAPI_CALL(env, napi_typeof(env, args[1], &valuetype1)); + + NAPI_ASSERT( + env, valuetype1 == napi_number, + "Wrong type of arguments. Expects an integer as second argument."); + + napi_value array = args[0]; + int32_t index; + NAPI_CALL(env, napi_get_value_int32(env, args[1], &index)); + + bool isarray; + NAPI_CALL(env, napi_is_array(env, array, &isarray)); + + if (!isarray) { + return NULL; + } + + bool has_element; + NAPI_CALL(env, napi_has_element(env, array, index, &has_element)); + + napi_value ret; + NAPI_CALL(env, napi_get_boolean(env, has_element, &ret)); + + return ret; +} + +static napi_value TestDeleteElement(napi_env env, napi_callback_info info) { + size_t argc = 2; + napi_value args[2]; + + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + NAPI_ASSERT(env, argc == 2, "Wrong number of arguments"); + + napi_valuetype valuetype0; + NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0)); + NAPI_ASSERT(env, valuetype0 == napi_object, + "Wrong type of arguments. Expects an array as first argument."); + + napi_valuetype valuetype1; + NAPI_CALL(env, napi_typeof(env, args[1], &valuetype1)); + NAPI_ASSERT( + env, valuetype1 == napi_number, + "Wrong type of arguments. Expects an integer as second argument."); + + napi_value array = args[0]; + int32_t index; + bool result; + napi_value ret; + + NAPI_CALL(env, napi_get_value_int32(env, args[1], &index)); + NAPI_CALL(env, napi_is_array(env, array, &result)); + + if (!result) { + return NULL; + } + + NAPI_CALL(env, napi_delete_element(env, array, index, &result)); + NAPI_CALL(env, napi_get_boolean(env, result, &ret)); + + return ret; +} + +static napi_value New(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + NAPI_ASSERT(env, argc >= 1, "Wrong number of arguments"); + + napi_valuetype valuetype0; + NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0)); + + NAPI_ASSERT(env, valuetype0 == napi_object, + "Wrong type of arguments. Expects an array as first argument."); + + napi_value ret; + NAPI_CALL(env, napi_create_array(env, &ret)); + + uint32_t i, length; + NAPI_CALL(env, napi_get_array_length(env, args[0], &length)); + + for (i = 0; i < length; i++) { + napi_value e; + NAPI_CALL(env, napi_get_element(env, args[0], i, &e)); + NAPI_CALL(env, napi_set_element(env, ret, i, e)); + } + + return ret; +} + +static napi_value NewWithLength(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + NAPI_ASSERT(env, argc >= 1, "Wrong number of arguments"); + + napi_valuetype valuetype0; + NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0)); + + NAPI_ASSERT( + env, valuetype0 == napi_number, + "Wrong type of arguments. Expects an integer the first argument."); + + int32_t array_length; + NAPI_CALL(env, napi_get_value_int32(env, args[0], &array_length)); + + napi_value ret; + NAPI_CALL(env, napi_create_array_with_length(env, array_length, &ret)); + + return ret; +} + +static napi_value Init(napi_env env, napi_value exports) { + napi_property_descriptor descriptors[] = { + DECLARE_NAPI_PROPERTY("TestGetElement", TestGetElement), + DECLARE_NAPI_PROPERTY("TestHasElement", TestHasElement), + DECLARE_NAPI_PROPERTY("TestDeleteElement", TestDeleteElement), + DECLARE_NAPI_PROPERTY("New", New), + DECLARE_NAPI_PROPERTY("NewWithLength", NewWithLength), + }; + + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(descriptors) / + sizeof(*descriptors), + descriptors)); + + return exports; +} + +NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) diff --git a/test/napi/test_napi_array.js b/test/napi/test_napi_array.js new file mode 100644 index 0000000000..37eb74d97c --- /dev/null +++ b/test/napi/test_napi_array.js @@ -0,0 +1,59 @@ +'use strict'; +var assert = require('assert'); +var common = require('common.js'); + +// Testing api calls for arrays +var test_array = require('./build/' + common.buildTypePath + + '/test_napi_array.node'); + +var array = [ + 1, + 9, + 48, + 13493, + 9459324, + { name: 'hello' }, + [ + 'world', + 'node', + 'abi' + ] +]; + +assert.throws( + function() { + test_array.TestGetElement(array, array.length + 1); + } +); + +assert.throws( + function() { + test_array.TestGetElement(array, -2); + } +); + +array.forEach(function(element, index) { + assert.strictEqual(test_array.TestGetElement(array, index), element); +}); + + +// assert.deepStrictEqual(test_array.New(array), array); + +assert(test_array.TestHasElement(array, 0)); +assert.strictEqual(test_array.TestHasElement(array, array.length + 1), false); + +assert(test_array.NewWithLength(0) instanceof Array); +assert(test_array.NewWithLength(1) instanceof Array); +// check max allowed length for an array 2^32 -1 +assert(test_array.NewWithLength(4294967295) instanceof Array); + +{ + // Verify that array elements can be deleted. + var arr = ['a', 'b', 'c', 'd']; + + assert.strictEqual(arr.length, 4); + assert.strictEqual(2 in arr, true); + assert.strictEqual(test_array.TestDeleteElement(arr, 2), true); + assert.strictEqual(arr.length, 4); + assert.strictEqual(2 in arr, false); +} diff --git a/test/napi/test_napi_async.c b/test/napi/test_napi_async.c new file mode 100644 index 0000000000..9b4392224b --- /dev/null +++ b/test/napi/test_napi_async.c @@ -0,0 +1,230 @@ +#include +#include +#if defined _WIN32 +#include +#else +#include +#endif +#include "common.h" + +// this needs to be greater than the thread pool size +#define MAX_CANCEL_THREADS 6 + +typedef struct { + int32_t _input; + int32_t _output; + napi_ref _callback; + napi_async_work _request; +} carrier; + +carrier the_carrier; +carrier async_carrier[MAX_CANCEL_THREADS]; + +void Execute(napi_env env, void* data) { +#if defined _WIN32 + Sleep(1000); +#else + sleep(1); +#endif + carrier* c = (carrier*)data; + + if (c != &the_carrier) { + napi_throw_type_error(env, NULL, "Wrong data parameter to Execute."); + return; + } + + c->_output = c->_input * 2; +} + +void Complete(napi_env env, napi_status status, void* data) { + carrier* c = (carrier*)data; + + if (c != &the_carrier) { + napi_throw_type_error(env, NULL, "Wrong data parameter to Complete."); + return; + } + + if (status != napi_ok) { + napi_throw_type_error(env, NULL, "Execute callback failed."); + return; + } + + napi_value argv[2]; + + NAPI_CALL_RETURN_VOID(env, napi_get_null(env, &argv[0])); + NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, c->_output, &argv[1])); + napi_value callback; + NAPI_CALL_RETURN_VOID(env, + napi_get_reference_value(env, c->_callback, &callback)); + napi_value global; + NAPI_CALL_RETURN_VOID(env, napi_get_global(env, &global)); + + napi_value result; + NAPI_CALL_RETURN_VOID(env, napi_call_function(env, global, callback, 2, argv, + &result)); + + NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, c->_callback)); + NAPI_CALL_RETURN_VOID(env, napi_delete_async_work(env, c->_request)); +} + +napi_value Test(napi_env env, napi_callback_info info) { + size_t argc = 3; + napi_value argv[3]; + napi_value _this; + napi_value resource_name; + void* data; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &_this, &data)); + NAPI_ASSERT(env, argc >= 3, "Not enough arguments, expected 2."); + + napi_valuetype t; + NAPI_CALL(env, napi_typeof(env, argv[0], &t)); + NAPI_ASSERT(env, t == napi_number, "Wrong first argument, integer expected."); + NAPI_CALL(env, napi_typeof(env, argv[1], &t)); + NAPI_ASSERT(env, t == napi_object, "Wrong second argument, object expected."); + NAPI_CALL(env, napi_typeof(env, argv[2], &t)); + NAPI_ASSERT(env, t == napi_function, + "Wrong third argument, function expected."); + + the_carrier._output = 0; + + NAPI_CALL(env, napi_get_value_int32(env, argv[0], &the_carrier._input)); + NAPI_CALL(env, + napi_create_reference(env, argv[2], 1, &the_carrier._callback)); + + NAPI_CALL(env, napi_create_string_utf8(env, "TestResource", NAPI_AUTO_LENGTH, + &resource_name)); + NAPI_CALL(env, napi_create_async_work(env, argv[1], resource_name, Execute, + Complete, &the_carrier, + &the_carrier._request)); + NAPI_CALL(env, napi_queue_async_work(env, the_carrier._request)); + + return NULL; +} + +void BusyCancelComplete(napi_env env, napi_status status, void* data) { + carrier* c = (carrier*)data; + NAPI_CALL_RETURN_VOID(env, napi_delete_async_work(env, c->_request)); +} + +void CancelComplete(napi_env env, napi_status status, void* data) { + carrier* c = (carrier*)data; + + if (status == napi_cancelled) { + // ok we got the status we expected so make the callback to + // indicate the cancel succeeded. + napi_value callback; + NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, c->_callback, + &callback)); + napi_value global; + NAPI_CALL_RETURN_VOID(env, napi_get_global(env, &global)); + napi_value result; + NAPI_CALL_RETURN_VOID(env, napi_call_function(env, global, callback, 0, + NULL, &result)); + } + + NAPI_CALL_RETURN_VOID(env, napi_delete_async_work(env, c->_request)); + NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, c->_callback)); +} + +void CancelExecute(napi_env env, void* data) { +#if defined _WIN32 + Sleep(1000); +#else + sleep(1); +#endif +} + +napi_value TestCancel(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value argv[1]; + napi_value _this; + napi_value resource_name; + void* data; + + NAPI_CALL(env, napi_create_string_utf8(env, "TestResource", NAPI_AUTO_LENGTH, + &resource_name)); + + // make sure the work we are going to cancel will not be + // able to start by using all the threads in the pool + for (int i = 1; i < MAX_CANCEL_THREADS; i++) { + NAPI_CALL(env, + napi_create_async_work(env, NULL, resource_name, CancelExecute, + BusyCancelComplete, &async_carrier[i], + &async_carrier[i]._request)); + NAPI_CALL(env, napi_queue_async_work(env, async_carrier[i]._request)); + } + + // now queue the work we are going to cancel and then cancel it. + // cancel will fail if the work has already started, but + // we have prevented it from starting by consuming all of the + // workers above. + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &_this, &data)); + NAPI_CALL(env, napi_create_async_work(env, NULL, resource_name, CancelExecute, + CancelComplete, &async_carrier[0], + &async_carrier[0]._request)); + NAPI_CALL(env, napi_create_reference(env, argv[0], 1, + &async_carrier[0]._callback)); + NAPI_CALL(env, napi_queue_async_work(env, async_carrier[0]._request)); + NAPI_CALL(env, napi_cancel_async_work(env, async_carrier[0]._request)); + return NULL; +} + +struct { + napi_ref ref; + napi_async_work work; +} repeated_work_info = { NULL, NULL }; + +static void RepeatedWorkerThread(napi_env env, void* data) { +} + +static void RepeatedWorkComplete(napi_env env, napi_status status, void* data) { + napi_value cb, js_status; + NAPI_CALL_RETURN_VOID(env, + napi_get_reference_value(env, repeated_work_info.ref, + &cb)); + NAPI_CALL_RETURN_VOID(env, + napi_delete_async_work(env, repeated_work_info.work)); + NAPI_CALL_RETURN_VOID(env, + napi_delete_reference(env, repeated_work_info.ref)); + repeated_work_info.work = NULL; + repeated_work_info.ref = NULL; + NAPI_CALL_RETURN_VOID(env, + napi_create_uint32(env, (uint32_t)status, &js_status)); + NAPI_CALL_RETURN_VOID(env, + napi_call_function(env, cb, cb, 1, &js_status, NULL)); +} + +static napi_value DoRepeatedWork(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value cb, name; + NAPI_ASSERT(env, repeated_work_info.ref == NULL, + "Reference left over from previous work"); + NAPI_ASSERT(env, repeated_work_info.work == NULL, + "Work pointer left over from previous work"); + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &cb, NULL, NULL)); + NAPI_CALL(env, napi_create_reference(env, cb, 1, &repeated_work_info.ref)); + NAPI_CALL(env, napi_create_string_utf8(env, "Repeated Work", NAPI_AUTO_LENGTH, + &name)); + NAPI_CALL(env, + napi_create_async_work(env, NULL, name, RepeatedWorkerThread, + RepeatedWorkComplete, &repeated_work_info, + &repeated_work_info.work)); + NAPI_CALL(env, napi_queue_async_work(env, repeated_work_info.work)); + return NULL; +} + +napi_value Init(napi_env env, napi_value exports) { + napi_property_descriptor properties[] = { + DECLARE_NAPI_PROPERTY("Test", Test), + DECLARE_NAPI_PROPERTY("TestCancel", TestCancel), + DECLARE_NAPI_PROPERTY("DoRepeatedWork", DoRepeatedWork), + }; + + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(properties) / + sizeof(*properties), + properties)); + + return exports; +} + +NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) diff --git a/test/napi/test_napi_async.js b/test/napi/test_napi_async.js new file mode 100644 index 0000000000..fd88594261 --- /dev/null +++ b/test/napi/test_napi_async.js @@ -0,0 +1,17 @@ +'use strict'; + +var common = require('common.js'); +var assert = require('assert'); +var test_async = require('./build/' + common.buildTypePath + + '/test_napi_async.node'); + +// Successful async execution and completion callback. +test_async.Test(5, {}, common.mustCall(function(err, val) { + console.log(err, val); + assert.strictEqual(err, null); + assert.strictEqual(val, 10); + process.nextTick(common.mustCall()); +})); + +// Async work item cancellation with callback. +test_async.TestCancel(common.mustCall()); diff --git a/test/napi/test_napi_buffer.c b/test/napi/test_napi_buffer.c new file mode 100644 index 0000000000..ec9c2b4fe4 --- /dev/null +++ b/test/napi/test_napi_buffer.c @@ -0,0 +1,135 @@ +#include +#include + +#include "common.h" +#include "node_api.h" + +static const char the_text[] = + "Lorem ipsum dolor sit amet, consectetur adipiscing elit."; +static const unsigned int buffer_size = sizeof(the_text) - 1; + +static int deleterCallCount = 0; +static void buffer_finalizer(napi_env env, void* data, void* finalize_hint) { + NAPI_ASSERT_RETURN_VOID(env, data != NULL && strcmp(data, the_text) == 0, + "invalid data"); + (void)finalize_hint; + free(data); + deleterCallCount++; +} + +static void noop_finilizer(napi_env env, void* data, void* finalize_hint) { + NAPI_ASSERT_RETURN_VOID(env, data != NULL && strcmp(data, the_text) == 0, + "invalid data"); + (void)finalize_hint; + deleterCallCount++; +} + +static napi_value new_buffer(napi_env env, napi_callback_info info) { + napi_value the_buffer; + char* the_copy; + + NAPI_CALL(env, napi_create_buffer(env, buffer_size, (void**)(&the_copy), + &the_buffer)); + NAPI_ASSERT(env, the_copy, "Failed to copy static text for newBuffer"); + memcpy(the_copy, the_text, buffer_size); + + return the_buffer; +} + +static napi_value new_external_buffer(napi_env env, napi_callback_info info) { + napi_value the_buffer; + char* the_copy = strdup(the_text); + NAPI_ASSERT(env, the_copy, + "Failed to copy static text for newExternalBuffer"); + NAPI_CALL(env, napi_create_external_buffer(env, buffer_size, the_copy, + buffer_finalizer, + NULL, // finalize_hint + &the_buffer)); + + return the_buffer; +} + +static napi_value get_deleter_call_count(napi_env env, + napi_callback_info info) { + napi_value callCount; + NAPI_CALL(env, napi_create_int32(env, deleterCallCount, &callCount)); + return callCount; +} + +static napi_value copy_buffer(napi_env env, napi_callback_info info) { + napi_value the_buffer; + NAPI_CALL(env, napi_create_buffer_copy(env, buffer_size, the_text, NULL, + &the_buffer)); + return the_buffer; +} + +static napi_value buffer_has_instance(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + NAPI_ASSERT(env, argc == 1, "Wrong number of arguments"); + napi_value the_buffer = args[0]; + bool hasInstance; + napi_valuetype theType; + NAPI_CALL(env, napi_typeof(env, the_buffer, &theType)); + NAPI_ASSERT(env, theType == napi_object, + "bufferHasInstance: instance is not an object"); + NAPI_CALL(env, napi_is_buffer(env, the_buffer, &hasInstance)); + NAPI_ASSERT(env, hasInstance, "bufferHasInstance: instance is not a buffer"); + napi_value returnValue; + NAPI_CALL(env, napi_get_boolean(env, hasInstance, &returnValue)); + return returnValue; +} + +static napi_value buffer_info(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + NAPI_ASSERT(env, argc == 1, "Wrong number of arguments"); + napi_value the_buffer = args[0]; + char* bufferData; + napi_value returnValue; + size_t bufferLength; + NAPI_CALL(env, napi_get_buffer_info(env, the_buffer, (void**)(&bufferData), + &bufferLength)); + NAPI_CALL(env, napi_get_boolean(env, bufferLength == buffer_size && + !strncmp(bufferData, the_text, + bufferLength), + &returnValue)); + return returnValue; +} + +static napi_value static_buffer(napi_env env, napi_callback_info info) { + napi_value the_buffer; + NAPI_CALL(env, napi_create_external_buffer(env, buffer_size, (void*)the_text, + noop_finilizer, + NULL, // finalize_hint + &the_buffer)); + return the_buffer; +} + +static napi_value init(napi_env env, napi_value exports) { + napi_value the_value; + + NAPI_CALL(env, + napi_create_string_utf8(env, the_text, buffer_size, &the_value)); + NAPI_CALL(env, napi_set_named_property(env, exports, "theText", the_value)); + + napi_property_descriptor methods[] = { + DECLARE_NAPI_PROPERTY("newBuffer", new_buffer), + DECLARE_NAPI_PROPERTY("newExternalBuffer", new_external_buffer), + DECLARE_NAPI_PROPERTY("getDeleterCallCount", get_deleter_call_count), + DECLARE_NAPI_PROPERTY("copyBuffer", copy_buffer), + DECLARE_NAPI_PROPERTY("bufferHasInstance", buffer_has_instance), + DECLARE_NAPI_PROPERTY("bufferInfo", buffer_info), + DECLARE_NAPI_PROPERTY("staticBuffer", static_buffer), + }; + + NAPI_CALL(env, napi_define_properties(env, exports, + sizeof(methods) / sizeof(methods[0]), + methods)); + + return exports; +} + +NAPI_MODULE(NODE_GYP_MODULE_NAME, init) diff --git a/test/napi/test_napi_buffer.js b/test/napi/test_napi_buffer.js new file mode 100644 index 0000000000..40d706a74b --- /dev/null +++ b/test/napi/test_napi_buffer.js @@ -0,0 +1,22 @@ +'use strict'; + +var global = process; +var common = require('common.js'); +var binding = require('./build/' + common.buildTypePath + + '/test_napi_buffer.node'); +var assert = require('assert'); + +assert.strictEqual(binding.newBuffer().toString(), binding.theText); +assert.strictEqual(binding.newExternalBuffer().toString(), binding.theText); +console.log('gc1'); +global.gc(); +assert.strictEqual(binding.getDeleterCallCount(), 1); +assert.strictEqual(binding.copyBuffer().toString(), binding.theText); + +var buffer = binding.staticBuffer(); +assert.strictEqual(binding.bufferHasInstance(buffer), true); +assert.strictEqual(binding.bufferInfo(buffer), true); +buffer = null; +global.gc(); +console.log('gc2'); +assert.strictEqual(binding.getDeleterCallCount(), 2); diff --git a/test/napi/test_napi_construct.c b/test/napi/test_napi_construct.c new file mode 100644 index 0000000000..e3dd952c63 --- /dev/null +++ b/test/napi/test_napi_construct.c @@ -0,0 +1,44 @@ +#include +#include "common.h" + +static napi_ref ConstructRef; + +static void cleanup(void* data) { + napi_env env = (napi_env)data; + napi_delete_reference(env, ConstructRef); +} + +napi_value Construct(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value argv[1]; + napi_value this; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &this, NULL)); + + NAPI_CALL(env, napi_set_named_property(env, this, "value", argv[0])); + + return NULL; +} + +napi_value Constructor(napi_env env, napi_callback_info info) { + napi_value construct; + NAPI_CALL(env, napi_get_reference_value(env, ConstructRef, &construct)); + + size_t argc = 1; + napi_value argv[1]; + napi_value result; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); + + NAPI_CALL(env, napi_new_instance(env, construct, argc, argv, &result)); + return result; +} + +NAPI_MODULE_INIT() { + napi_value construct; + NAPI_CALL(env, napi_create_function(env, "Constructor", NAPI_AUTO_LENGTH, + Construct, NULL, &construct)); + NAPI_CALL(env, napi_create_reference(env, construct, 1, &ConstructRef)); + NAPI_CALL(env, napi_add_env_cleanup_hook(env, cleanup, env)); + + SET_NAMED_METHOD(env, exports, "Constructor", Constructor); + return exports; +} diff --git a/test/napi/test_napi_construct.js b/test/napi/test_napi_construct.js new file mode 100644 index 0000000000..6c3e92bd43 --- /dev/null +++ b/test/napi/test_napi_construct.js @@ -0,0 +1,8 @@ +'use strict'; +var assert = require('assert'); +var common = require('common.js'); +var test = require('./build/' + common.buildTypePath + + '/test_napi_construct.node'); + +var val = test.Constructor(123); +assert.strictEqual(val.value, 123); diff --git a/test/napi/test_napi_conversions.c b/test/napi/test_napi_conversions.c new file mode 100644 index 0000000000..63fcf9a6db --- /dev/null +++ b/test/napi/test_napi_conversions.c @@ -0,0 +1,155 @@ +#include "common.h" +#include "node_api.h" + +static napi_value AsBool(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + bool value; + NAPI_CALL(env, napi_get_value_bool(env, args[0], &value)); + + napi_value output; + NAPI_CALL(env, napi_get_boolean(env, value, &output)); + + return output; +} + +static napi_value AsInt32(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + int32_t value; + NAPI_CALL(env, napi_get_value_int32(env, args[0], &value)); + + napi_value output; + NAPI_CALL(env, napi_create_int32(env, value, &output)); + + return output; +} + +static napi_value AsUInt32(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + uint32_t value; + NAPI_CALL(env, napi_get_value_uint32(env, args[0], &value)); + + napi_value output; + NAPI_CALL(env, napi_create_uint32(env, value, &output)); + + return output; +} + +static napi_value AsInt64(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + int64_t value; + NAPI_CALL(env, napi_get_value_int64(env, args[0], &value)); + + napi_value output; + NAPI_CALL(env, napi_create_int64(env, (double)value, &output)); + + return output; +} + +static napi_value AsDouble(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + double value; + NAPI_CALL(env, napi_get_value_double(env, args[0], &value)); + + napi_value output; + NAPI_CALL(env, napi_create_double(env, value, &output)); + + return output; +} + +static napi_value AsString(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + char value[100]; + NAPI_CALL(env, napi_get_value_string_utf8(env, args[0], value, sizeof(value), + NULL)); + + napi_value output; + NAPI_CALL(env, + napi_create_string_utf8(env, value, NAPI_AUTO_LENGTH, &output)); + + return output; +} + +static napi_value ToBool(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + napi_value output; + NAPI_CALL(env, napi_coerce_to_bool(env, args[0], &output)); + + return output; +} + +static napi_value ToNumber(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + napi_value output; + NAPI_CALL(env, napi_coerce_to_number(env, args[0], &output)); + + return output; +} + +static napi_value ToObject(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + napi_value output; + NAPI_CALL(env, napi_coerce_to_object(env, args[0], &output)); + + return output; +} + +static napi_value ToString(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + napi_value output; + NAPI_CALL(env, napi_coerce_to_string(env, args[0], &output)); + + return output; +} + +static napi_value Init(napi_env env, napi_value exports) { + napi_property_descriptor descriptors[] = { + DECLARE_NAPI_PROPERTY("asBool", AsBool), + DECLARE_NAPI_PROPERTY("asInt32", AsInt32), + DECLARE_NAPI_PROPERTY("asUInt32", AsUInt32), + DECLARE_NAPI_PROPERTY("asInt64", AsInt64), + DECLARE_NAPI_PROPERTY("asDouble", AsDouble), + DECLARE_NAPI_PROPERTY("asString", AsString), + DECLARE_NAPI_PROPERTY("toBool", ToBool), + DECLARE_NAPI_PROPERTY("toNumber", ToNumber), + DECLARE_NAPI_PROPERTY("toObject", ToObject), + DECLARE_NAPI_PROPERTY("toString", ToString), + }; + + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(descriptors) / + sizeof(*descriptors), + descriptors)); + + return exports; +} + +NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) diff --git a/test/napi/test_napi_conversions.js b/test/napi/test_napi_conversions.js new file mode 100644 index 0000000000..a73d96c834 --- /dev/null +++ b/test/napi/test_napi_conversions.js @@ -0,0 +1,178 @@ +'use strict'; +var assert = require('assert'); +var common = require('common.js'); +var test = require('./build/' + common.buildTypePath + + '/test_napi_conversions.node'); + +assert.strictEqual(false, test.asBool(false)); +assert.strictEqual(true, test.asBool(true)); +assert.throws(function() { test.asBool(undefined) }, Error); +assert.throws(function() { test.asBool(null) }, Error); +assert.throws(function() { test.asBool(Number.NaN) }, Error); +assert.throws(function() { test.asBool(0) }, Error); +assert.throws(function() { test.asBool('') }, Error); +assert.throws(function() { test.asBool('0') }, Error); +assert.throws(function() { test.asBool(1) }, Error); +assert.throws(function() { test.asBool('1') }, Error); +assert.throws(function() { test.asBool('true') }, Error); +assert.throws(function() { test.asBool({}) }, Error); +assert.throws(function() { test.asBool([]) }, Error); + +[test.asInt32, test.asUInt32, test.asInt64].forEach(function (asInt) { + assert.strictEqual(0, asInt(0)); + assert.strictEqual(1, asInt(1)); + assert.strictEqual(1, asInt(1.0)); + assert.strictEqual(1, asInt(1.1)); + assert.strictEqual(1, asInt(1.9)); + assert.strictEqual(0, asInt(0.9)); + assert.strictEqual(999, asInt(999.9)); + assert.strictEqual(0, asInt(Number.NaN)); + assert.throws(function() { asInt(undefined) }, Error); + assert.throws(function() { asInt(null) }, Error); + assert.throws(function() { asInt(false) }, Error); + assert.throws(function() { asInt('') }, Error); + assert.throws(function() { asInt('1') }, Error); + assert.throws(function() { asInt({}) }, Error); + assert.throws(function() { asInt([]) }, Error); +}); + +assert.strictEqual(-1, test.asInt32(-1)); +assert.strictEqual(-1, test.asInt64(-1)); +assert.strictEqual(Math.pow(2, 32) - 1, test.asUInt32(-1)); +assert.strictEqual(0, test.asDouble(0)); +assert.strictEqual(1, test.asDouble(1)); +assert.strictEqual(1.0, test.asDouble(1.0)); + +assert.strictEqual(1.1, test.asDouble(1.1)); +assert.strictEqual(1.9, test.asDouble(1.9)); +assert.strictEqual(0.9, test.asDouble(0.9)); +assert.strictEqual(999.9, test.asDouble(999.9)); +assert.strictEqual(-1, test.asDouble(-1)); +assert.throws(function() { test.asDouble(undefined) }, Error); +assert.throws(function() { test.asDouble(null) }, Error); +assert.throws(function() { test.asDouble(false) }, Error); +assert.throws(function() { test.asDouble('') }, Error); +assert.throws(function() { test.asDouble('1') }, Error); +assert.throws(function() { test.asDouble({}) }, Error); +assert.throws(function() { test.asDouble([]) }, Error); + +assert.strictEqual('', test.asString('')); +assert.strictEqual('test', test.asString('test')); +assert.throws(function() { test.asString(undefined) }, Error); +assert.throws(function() { test.asString(null) }, Error); +assert.throws(function() { test.asString(false) }, Error); +assert.throws(function() { test.asString(1) }, Error); +assert.throws(function() { test.asString(1.1) }, Error); +assert.throws(function() { test.asString(Number.NaN) }, Error); +assert.throws(function() { test.asString({}) }, Error); +assert.throws(function() { test.asString([]) }, Error); + +assert.strictEqual(true, test.toBool(true)); +assert.strictEqual(true, test.toBool(1)); +assert.strictEqual(true, test.toBool(-1)); +assert.strictEqual(true, test.toBool('true')); +assert.strictEqual(true, test.toBool('false')); +assert.strictEqual(true, test.toBool({})); +assert.strictEqual(true, test.toBool([])); +assert.strictEqual(false, test.toBool(false)); +assert.strictEqual(false, test.toBool(undefined)); +assert.strictEqual(false, test.toBool(null)); +assert.strictEqual(false, test.toBool(0)); +assert.strictEqual(false, test.toBool(Number.NaN)); +assert.strictEqual(false, test.toBool('')); + +assert.strictEqual(0, test.toNumber(0)); +assert.strictEqual(1, test.toNumber(1)); +assert.strictEqual(1.1, test.toNumber(1.1)); +assert.strictEqual(-1, test.toNumber(-1)); +assert.strictEqual(0, test.toNumber('0')); +assert.strictEqual(1, test.toNumber('1')); +assert.strictEqual(1.1, test.toNumber('1.1')); +assert.strictEqual(0, test.toNumber([])); +assert.strictEqual(0, test.toNumber(false)); +assert.strictEqual(0, test.toNumber(null)); +assert.strictEqual(0, test.toNumber('')); + +Number.isNaN = Number.isNaN || function(value) { + return value !== value; +} + +assert(Number.isNaN(test.asDouble(Number.NaN))); +assert(Number.isNaN(test.toNumber(Number.NaN))); +assert(Number.isNaN(test.toNumber({}))); +assert(Number.isNaN(test.toNumber(undefined))); + +assert.deepStrictEqual = assert.deepStrictEqual || function(expected, value) { + var keys = Object.keys(value); + if ((typeof expected !== typeof value) + || (keys.length !== Object.keys(expected).length)) { + assert(false); + } + + if (keys.length > 0) { + for (var key in keys) { + if (typeof value[keys[key]] !== 'object') { + assert.strictEqual(expected[keys[key]], value[keys[key]]); + } else { + assert.deepStrictEqual(expected[keys[key]], value[keys[key]]); + } + } + } else if (typeof value.valueOf() !== 'object') { + assert.strictEqual(expected.valueOf(), value.valueOf()); + } +} + +assert.notDeepStrictEqual = assert.notDeepStrictEqual || +function(expected, value) { + if ((typeof expected !== typeof value) + || (Object.keys(value).length !== Object.keys(expected).length)) { + return; + } + + var keys = Object.keys(value); + if (keys.length > 0) { + for (var key in keys) { + if (typeof value[keys[key]] !== 'object') { + assert.notStrictEqual(expected[keys[key]], value[keys[key]]); + } else { + assert.notDeepStrictEqual(expected[keys[key]], value[keys[key]]); + } + } + } else if (typeof value.valueOf() !== 'object') { + assert.notStrictEqual(expected.valueOf(), value.valueOf()); + } +} + +assert.deepStrictEqual({}, test.toObject({})); +assert.deepStrictEqual({ 'test': 1 }, test.toObject({ 'test': 1 })); +assert.deepStrictEqual([], test.toObject([])); +assert.deepStrictEqual([ 1, 2, 3 ], test.toObject([ 1, 2, 3 ])); +assert.deepStrictEqual(new Boolean(false), test.toObject(false)); +assert.deepStrictEqual(new Boolean(true), test.toObject(true)); +assert.deepStrictEqual(new String(''), test.toObject('')); +assert.deepStrictEqual(new Number(0), test.toObject(0)); +assert.notDeepStrictEqual(new Number(Number.NaN), test.toObject(Number.NaN)); +assert.notDeepStrictEqual(new Boolean(true), test.toObject(false)); +assert.notDeepStrictEqual(new Boolean(false), test.toObject(true)); +assert.notDeepStrictEqual(test.toObject(false), false); +assert.notDeepStrictEqual(test.toObject(true), true); +assert.notDeepStrictEqual(test.toObject(''), ''); +assert.notDeepStrictEqual(test.toObject(0), 0); + +assert(!Number.isNaN(test.toObject(Number.NaN))); + +assert.strictEqual('', test.toString('')); +assert.strictEqual('test', test.toString('test')); +assert.strictEqual('undefined', test.toString(undefined)); +assert.strictEqual('null', test.toString(null)); +assert.strictEqual('false', test.toString(false)); +assert.strictEqual('true', test.toString(true)); +assert.strictEqual('0', test.toString(0)); +assert.strictEqual('1.1', test.toString(1.1)); +assert.strictEqual('NaN', test.toString(Number.NaN)); +assert.strictEqual('[object Object]', test.toString({})); +assert.strictEqual('test', test.toString({ + toString: function() { return 'test' } +})); +assert.strictEqual('', test.toString([])); +assert.strictEqual('1,2,3', test.toString([ 1, 2, 3 ])); diff --git a/test/napi/test_napi_create_error.js b/test/napi/test_napi_create_error.js new file mode 100644 index 0000000000..1a38b7b914 --- /dev/null +++ b/test/napi/test_napi_create_error.js @@ -0,0 +1,26 @@ +var common = require('common.js'); +var addon = require('./build/' + common.buildTypePath + + '/test_napi_error_handling'); +var assert = require('assert'); + +var ERROR_CODE = "ErrorCode"; +var ERROR_MSG = "ErrorMSG" + +var error = addon.CreateError(ERROR_CODE, ERROR_MSG); + +assert(error.code == ERROR_CODE); +assert(error.message == ERROR_MSG); + +assert(error instanceof Error); + +var typeError = addon.CreateTypeError(ERROR_CODE, ERROR_MSG); +assert(typeError.code == ERROR_CODE); +assert(typeError.message == ERROR_MSG); + +assert(typeError instanceof TypeError); + +var rangeError = addon.CreateRangeError(ERROR_CODE, ERROR_MSG); +assert(rangeError.code == ERROR_CODE); +assert(rangeError.message == ERROR_MSG); + +assert(rangeError instanceof RangeError); diff --git a/test/napi/test_napi_dataview.c b/test/napi/test_napi_dataview.c new file mode 100644 index 0000000000..5a6111b835 --- /dev/null +++ b/test/napi/test_napi_dataview.c @@ -0,0 +1,101 @@ +#include "common.h" +#include "node_api.h" + +#include + +static napi_value create_dataview(napi_env env, napi_callback_info info) { + size_t argc = 3; + napi_value args[3]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + NAPI_ASSERT(env, argc == 3, "Wrong number of arguments"); + + napi_valuetype valuetype0; + napi_value arraybuffer = args[0]; + + NAPI_CALL(env, napi_typeof(env, arraybuffer, &valuetype0)); + NAPI_ASSERT(env, valuetype0 == napi_object, + "Wrong type of arguments. Expects a ArrayBuffer as the first " + "argument."); + + bool is_arraybuffer; + NAPI_CALL(env, napi_is_arraybuffer(env, arraybuffer, &is_arraybuffer)); + NAPI_ASSERT(env, is_arraybuffer, + "Wrong type of arguments. Expects a ArrayBuffer as the first " + "argument."); + + napi_valuetype valuetype1; + NAPI_CALL(env, napi_typeof(env, args[1], &valuetype1)); + + NAPI_ASSERT(env, valuetype1 == napi_number, + "Wrong type of arguments. Expects a number as second argument."); + + size_t byte_offset = 0; + NAPI_CALL(env, + napi_get_value_uint32(env, args[1], (uint32_t*)(&byte_offset))); + + napi_valuetype valuetype2; + NAPI_CALL(env, napi_typeof(env, args[2], &valuetype2)); + + NAPI_ASSERT(env, valuetype2 == napi_number, + "Wrong type of arguments. Expects a number as third argument."); + + size_t length = 0; + NAPI_CALL(env, napi_get_value_uint32(env, args[2], (uint32_t*)(&length))); + + napi_value output_dataview; + NAPI_CALL(env, napi_create_dataview(env, length, arraybuffer, byte_offset, + &output_dataview)); + + return output_dataview; +} + +static napi_value create_data_view_from_js_dataview(napi_env env, + napi_callback_info info) { + size_t argc = 1; + napi_value args[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + NAPI_ASSERT(env, argc == 1, "Wrong number of arguments"); + + napi_valuetype valuetype; + napi_value input_dataview = args[0]; + + NAPI_CALL(env, napi_typeof(env, input_dataview, &valuetype)); + NAPI_ASSERT(env, valuetype == napi_object, + "Wrong type of arguments. Expects a DataView as the first " + "argument."); + + bool is_dataview; + NAPI_CALL(env, napi_is_dataview(env, input_dataview, &is_dataview)); + NAPI_ASSERT(env, is_dataview, + "Wrong type of arguments. Expects a DataView as the first " + "argument."); + size_t byte_offset = 0; + size_t length = 0; + napi_value buffer; + NAPI_CALL(env, napi_get_dataview_info(env, input_dataview, &length, NULL, + &buffer, &byte_offset)); + + napi_value output_dataview; + NAPI_CALL(env, napi_create_dataview(env, length, buffer, byte_offset, + &output_dataview)); + + + return output_dataview; +} + +static napi_value init(napi_env env, napi_value exports) { + napi_property_descriptor descriptors[] = + { DECLARE_NAPI_PROPERTY("CreateDataView", create_dataview), + DECLARE_NAPI_PROPERTY("CreateDataViewFromJSDataView", + create_data_view_from_js_dataview) }; + + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(descriptors) / + sizeof(*descriptors), + descriptors)); + + return exports; +} + +NAPI_MODULE(NODE_GYP_MODULE_NAME, init) diff --git a/test/napi/test_napi_dataview.js b/test/napi/test_napi_dataview.js new file mode 100644 index 0000000000..b4e2b8a53a --- /dev/null +++ b/test/napi/test_napi_dataview.js @@ -0,0 +1,25 @@ +'use strict'; +var assert = require('assert'); +var common = require('common.js'); + +// Testing api calls for arrays +var test_dataview = require('./build/' + common.buildTypePath + + '/test_napi_dataview.node'); + +// Test for creating dataview +{ + var buffer = new ArrayBuffer(128); + var template = new DataView(buffer); + + var theDataview = test_dataview.CreateDataViewFromJSDataView(template); + assert(theDataview instanceof DataView, + 'Expect ' + theDataview + ' to be a DataView'); +} + +// Test for creating dataview with invalid range +{ + var buffer = new ArrayBuffer(128); + assert.throws(function() { + test_dataview.CreateDataView(buffer, 10, 200); + }, RangeError); +} diff --git a/test/napi/test_napi_env.js b/test/napi/test_napi_env.js new file mode 100644 index 0000000000..bb80b45c49 --- /dev/null +++ b/test/napi/test_napi_env.js @@ -0,0 +1,11 @@ +'use strict'; + +var common = require('common.js'); +var storeEnv = require('./build/' + common.buildTypePath + + '/test_napi_env_store.node'); +var compareEnv = require('./build/' + common.buildTypePath + + '/test_napi_env_compare.node'); +var assert = require('assert'); + +// N-API environment pointers in two different modules must be different +assert.strictEqual(compareEnv(storeEnv), true); diff --git a/test/napi/test_napi_env_compare.c b/test/napi/test_napi_env_compare.c new file mode 100644 index 0000000000..f6d082ce8f --- /dev/null +++ b/test/napi/test_napi_env_compare.c @@ -0,0 +1,23 @@ +#include +#include "common.h" + +static napi_value compare(napi_env env, napi_callback_info info) { + napi_value external; + size_t argc = 1; + void* data; + napi_value return_value; + + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &external, NULL, NULL)); + NAPI_CALL(env, napi_get_value_external(env, external, &data)); + NAPI_CALL(env, napi_get_boolean(env, ((napi_env)data) == env, &return_value)); + + return return_value; +} + +static napi_value Init(napi_env env, napi_value exports) { + NAPI_CALL(env, napi_create_function(env, "exports", NAPI_AUTO_LENGTH, compare, + NULL, &exports)); + return exports; +} + +NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) diff --git a/test/napi/test_napi_env_store.c b/test/napi/test_napi_env_store.c new file mode 100644 index 0000000000..2c9ee14c79 --- /dev/null +++ b/test/napi/test_napi_env_store.c @@ -0,0 +1,10 @@ +#include +#include "common.h" + +static napi_value Init(napi_env env, napi_value exports) { + napi_value external; + NAPI_CALL(env, napi_create_external(env, env, NULL, NULL, &external)); + return external; +} + +NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) diff --git a/test/napi/test_napi_error_handling.c b/test/napi/test_napi_error_handling.c new file mode 100644 index 0000000000..89e6f45570 --- /dev/null +++ b/test/napi/test_napi_error_handling.c @@ -0,0 +1,169 @@ +#include +#include +#include +#include "common.h" + +#define ERROR_CODE "ErrorCODE" +#define ERROR_MSG "ErrorMSG" + +napi_value Throw(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value argv[1]; + napi_status status; + status = napi_get_cb_info(env, info, &argc, argv, NULL, NULL); + assert(status == napi_ok); + + status = napi_throw(env, argv[0]); + assert(status == napi_ok); + + return NULL; +} + +napi_value ThrowError(napi_env env, napi_callback_info info) { + napi_status status; + + status = napi_throw_error(env, ERROR_CODE, ERROR_MSG); + assert(status == napi_ok); + + return NULL; +} + +napi_value ThrowTypeError(napi_env env, napi_callback_info info) { + napi_status status; + + status = napi_throw_type_error(env, ERROR_CODE, ERROR_MSG); + assert(status == napi_ok); + + return NULL; +} + +napi_value ThrowRangeError(napi_env env, napi_callback_info info) { + napi_status status; + + status = napi_throw_range_error(env, ERROR_CODE, ERROR_MSG); + assert(status == napi_ok); + + return NULL; +} + +napi_value IsError(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value argv[1]; + napi_value result; + napi_status status; + bool res; + + status = napi_get_cb_info(env, info, &argc, argv, NULL, NULL); + assert(status == napi_ok); + + status = napi_is_error(env, argv[0], &res); + assert(status == napi_ok); + + status = napi_get_boolean(env, res, &result); + assert(status == napi_ok); + + return result; +} + +napi_value CreateError(napi_env env, napi_callback_info info) { + size_t argc = 2; + napi_value argv[2]; + napi_value result; + napi_status status; + + status = napi_get_cb_info(env, info, &argc, argv, NULL, NULL); + assert(status == napi_ok); + + status = napi_create_error(env, argv[0], argv[1], &result); + assert(status == napi_ok); + + return result; +} + +napi_value CreateTypeError(napi_env env, napi_callback_info info) { + size_t argc = 2; + napi_value argv[2]; + napi_value result; + napi_status status; + + status = napi_get_cb_info(env, info, &argc, argv, NULL, NULL); + assert(status == napi_ok); + + status = napi_create_type_error(env, argv[0], argv[1], &result); + assert(status == napi_ok); + + return result; +} + +napi_value CreateRangeError(napi_env env, napi_callback_info info) { + size_t argc = 2; + napi_value argv[2]; + napi_value result; + napi_status status; + + status = napi_get_cb_info(env, info, &argc, argv, NULL, NULL); + assert(status == napi_ok); + + status = napi_create_range_error(env, argv[0], argv[1], &result); + assert(status == napi_ok); + + return result; +} + +napi_value GetandClearLastException(napi_env env, napi_callback_info info) { + napi_status status; + napi_value result; + + status = napi_get_and_clear_last_exception(env, &result); + assert(status == napi_ok); + + return result; +} + +napi_value IsExceptionPending(napi_env env, napi_callback_info info) { + napi_status status; + bool res; + napi_value result; + + status = napi_is_exception_pending(env, &res); + assert(status == napi_ok); + + status = napi_get_boolean(env, res, &result); + assert(status == napi_ok); + + return result; +} + +napi_value FatalException(napi_env env, napi_callback_info info) { + napi_status status; + size_t argc = 1; + napi_value argv[1]; + + status = napi_get_cb_info(env, info, &argc, argv, NULL, NULL); + assert(status == napi_ok); + + status = napi_fatal_exception(env, argv[0]); + assert(status == napi_ok); + + return NULL; +} + + +napi_value Init(napi_env env, napi_value exports) { + SET_NAMED_METHOD(env, exports, "Throw", Throw); + SET_NAMED_METHOD(env, exports, "ThrowError", ThrowError); + SET_NAMED_METHOD(env, exports, "ThrowTypeError", ThrowTypeError); + SET_NAMED_METHOD(env, exports, "ThrowRangeError", ThrowRangeError); + SET_NAMED_METHOD(env, exports, "IsError", IsError); + SET_NAMED_METHOD(env, exports, "CreateError", CreateError); + SET_NAMED_METHOD(env, exports, "CreateTypeError", CreateTypeError); + SET_NAMED_METHOD(env, exports, "CreateRangeError", CreateRangeError); + SET_NAMED_METHOD(env, exports, "GetandClearLastException", + GetandClearLastException); + SET_NAMED_METHOD(env, exports, "IsExceptionPending", IsExceptionPending); + SET_NAMED_METHOD(env, exports, "FatalException", FatalException); + + return exports; +} + +NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) diff --git a/test/napi/test_napi_exception.js b/test/napi/test_napi_exception.js new file mode 100644 index 0000000000..270cbdd3a6 --- /dev/null +++ b/test/napi/test_napi_exception.js @@ -0,0 +1,16 @@ +var common = require('common.js'); +var addon = require('./build/' + common.buildTypePath + + '/test_napi_error_handling'); +var assert = require('assert'); + +var ERROR_MSG = "ErrorMSG"; + +process.on("uncaughtException", function (e) { + assert(e.message === ERROR_MSG); +}); + +assert(addon.GetandClearLastException() === undefined); + +var err = new Error(ERROR_MSG); + +addon.FatalException(err); diff --git a/test/napi/test_napi_general.c b/test/napi/test_napi_general.c new file mode 100644 index 0000000000..f15f89287a --- /dev/null +++ b/test/napi/test_napi_general.c @@ -0,0 +1,82 @@ +/* Copyright 2019-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 "common.h" +#include "node_api.h" + +static napi_value get_null(napi_env env, napi_callback_info info) { + napi_value result; + NAPI_CALL(env, napi_get_null(env, &result)); + return result; +} + +static napi_value get_undefined(napi_env env, napi_callback_info info) { + napi_value result; + NAPI_CALL(env, napi_get_undefined(env, &result)); + return result; +} + +static napi_value test_typeof(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + napi_valuetype argument_type; + NAPI_CALL(env, napi_typeof(env, args[0], &argument_type)); + + napi_value result = NULL; + if (argument_type == napi_number) { + NAPI_CALL(env, napi_create_string_utf8(env, "number", NAPI_AUTO_LENGTH, + &result)); + } else if (argument_type == napi_string) { + NAPI_CALL(env, napi_create_string_utf8(env, "string", NAPI_AUTO_LENGTH, + &result)); + } else if (argument_type == napi_function) { + NAPI_CALL(env, napi_create_string_utf8(env, "function", NAPI_AUTO_LENGTH, + &result)); + } else if (argument_type == napi_object) { + NAPI_CALL(env, napi_create_string_utf8(env, "object", NAPI_AUTO_LENGTH, + &result)); + } else if (argument_type == napi_boolean) { + NAPI_CALL(env, napi_create_string_utf8(env, "boolean", NAPI_AUTO_LENGTH, + &result)); + } else if (argument_type == napi_undefined) { + NAPI_CALL(env, napi_create_string_utf8(env, "undefined", NAPI_AUTO_LENGTH, + &result)); + } else if (argument_type == napi_symbol) { + NAPI_CALL(env, napi_create_string_utf8(env, "symbol", NAPI_AUTO_LENGTH, + &result)); + } else if (argument_type == napi_null) { + NAPI_CALL(env, + napi_create_string_utf8(env, "null", NAPI_AUTO_LENGTH, &result)); + } + return result; +} + +static napi_value init(napi_env env, napi_value exports) { + napi_property_descriptor descriptors[] = { + DECLARE_NAPI_PROPERTY("GetNull", get_null), + DECLARE_NAPI_PROPERTY("GetUndefined", get_undefined), + DECLARE_NAPI_PROPERTY("TypeOf", test_typeof), + }; + + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(descriptors) / + sizeof(*descriptors), + descriptors)); + + return exports; +} + +NAPI_MODULE(NODE_GYP_MODULE_NAME, init) diff --git a/test/napi/test_napi_general.js b/test/napi/test_napi_general.js new file mode 100644 index 0000000000..67e402d57e --- /dev/null +++ b/test/napi/test_napi_general.js @@ -0,0 +1,35 @@ +/* Copyright 2019-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. + */ + +'use strict'; +var assert = require('assert'); +var common = require('common.js'); + +var test_general = require('./build/' + common.buildTypePath + + '/test_napi_general.node'); + +assert.strictEqual(test_general.GetUndefined(), undefined); +assert.strictEqual(test_general.GetNull(), null); + +[ + 123, + 'test string', + function() {}, + new Object(), + true, + undefined +].forEach(function(val) { + assert.strictEqual(test_general.TypeOf(val), typeof val); +}); diff --git a/test/napi/test_napi_general_es2015.js b/test/napi/test_napi_general_es2015.js new file mode 100644 index 0000000000..338f6a5ec9 --- /dev/null +++ b/test/napi/test_napi_general_es2015.js @@ -0,0 +1,44 @@ +/* Copyright 2019-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. + */ + +'use strict'; +var assert = require('assert'); + +var common = require('common.js'); +var test_general = require('./build/' + common.buildTypePath + + '/test_napi_general.node'); + +assert.strictEqual(test_general.GetUndefined(), undefined); +assert.strictEqual(test_general.GetNull(), null); + +var buffer = new ArrayBuffer(16); + +[ + buffer, + new Int8Array(buffer), + new Uint8Array(buffer), + new Uint8ClampedArray(buffer), + new Int16Array(buffer), + new Uint16Array(buffer), + new Int32Array(buffer), + new Uint32Array(buffer), + new Float32Array(buffer), + new Float64Array(buffer), + + new Promise(function(){}), + Symbol(), +].forEach(function(val) { + assert.strictEqual(test_general.TypeOf(val), typeof val); +}); diff --git a/test/napi/test_napi_handle_scope.c b/test/napi/test_napi_handle_scope.c new file mode 100644 index 0000000000..004a0c9abf --- /dev/null +++ b/test/napi/test_napi_handle_scope.c @@ -0,0 +1,98 @@ +/* Copyright 2019-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 "common.h" +#include "node_api.h" + +#include + +static napi_value new_scope(napi_env env, napi_callback_info info) { + napi_handle_scope scope; + napi_value output = NULL; + + NAPI_CALL(env, napi_open_handle_scope(env, &scope)); + NAPI_CALL(env, napi_create_object(env, &output)); + NAPI_CALL(env, napi_close_handle_scope(env, scope)); + return NULL; +} + +static napi_value new_scope_escape(napi_env env, napi_callback_info info) { + napi_escapable_handle_scope scope; + napi_value output = NULL; + napi_value escapee = NULL; + + NAPI_CALL(env, napi_open_escapable_handle_scope(env, &scope)); + NAPI_CALL(env, napi_create_object(env, &output)); + NAPI_CALL(env, napi_escape_handle(env, scope, output, &escapee)); + NAPI_CALL(env, napi_close_escapable_handle_scope(env, scope)); + return escapee; +} + +static napi_value new_scope_escape_twice(napi_env env, + napi_callback_info info) { + napi_escapable_handle_scope scope; + napi_value output = NULL; + napi_value escapee = NULL; + napi_status status; + + NAPI_CALL(env, napi_open_escapable_handle_scope(env, &scope)); + NAPI_CALL(env, napi_create_object(env, &output)); + NAPI_CALL(env, napi_escape_handle(env, scope, output, &escapee)); + status = napi_escape_handle(env, scope, output, &escapee); + NAPI_ASSERT(env, status == napi_escape_called_twice, "Escaping twice fails"); + NAPI_CALL(env, napi_close_escapable_handle_scope(env, scope)); + return NULL; +} + +static napi_value new_scope_with_exception(napi_env env, + napi_callback_info info) { + napi_handle_scope scope; + size_t argc; + napi_value exception_function; + napi_status status; + napi_value output = NULL; + + NAPI_CALL(env, napi_open_handle_scope(env, &scope)); + NAPI_CALL(env, napi_create_object(env, &output)); + + argc = 1; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &exception_function, NULL, + NULL)); + + status = napi_call_function(env, output, exception_function, 0, NULL, NULL); + NAPI_ASSERT(env, status == napi_pending_exception, + "Function should have thrown."); + + // Closing a handle scope should still work while an exception is pending. + NAPI_CALL(env, napi_close_handle_scope(env, scope)); + return NULL; +} + +static napi_value init(napi_env env, napi_value exports) { + napi_property_descriptor properties[] = { + DECLARE_NAPI_PROPERTY("NewScope", new_scope), + DECLARE_NAPI_PROPERTY("NewScopeEscape", new_scope_escape), + DECLARE_NAPI_PROPERTY("NewScopeEscapeTwice", new_scope_escape_twice), + DECLARE_NAPI_PROPERTY("NewScopeWithException", new_scope_with_exception), + }; + + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(properties) / + sizeof(*properties), + properties)); + + return exports; +} + +NAPI_MODULE(NODE_GYP_MODULE_NAME, init); diff --git a/test/napi/test_napi_handle_scope.js b/test/napi/test_napi_handle_scope.js new file mode 100644 index 0000000000..59be7c9f24 --- /dev/null +++ b/test/napi/test_napi_handle_scope.js @@ -0,0 +1,19 @@ +var common = require('common.js'); +var assert = require('assert'); +var testHandleScope = require('./build/' + common.buildTypePath + + '/test_napi_handle_scope.node'); + +testHandleScope.NewScope(); + +assert(testHandleScope.NewScopeEscape() instanceof Object); + +testHandleScope.NewScopeEscapeTwice(); + +assert.throws( + function() { + testHandleScope.NewScopeWithException(function() { + throw new RangeError(); + }); + }, + RangeError +); diff --git a/test/napi/test_napi_is_error.js b/test/napi/test_napi_is_error.js new file mode 100644 index 0000000000..5328f06223 --- /dev/null +++ b/test/napi/test_napi_is_error.js @@ -0,0 +1,13 @@ +var common = require('common.js'); +var addon = require('./build/' + common.buildTypePath + + '/test_napi_error_handling'); +var assert = require('assert'); + +var err = new Error("ErrorMSG"); +try { + var c = true; + throw c +} catch (e) { + assert(addon.IsError(e) === false); +} +assert(addon.IsError(err)); diff --git a/test/napi/test_napi_make_callback.c b/test/napi/test_napi_make_callback.c new file mode 100644 index 0000000000..07c8fb8c62 --- /dev/null +++ b/test/napi/test_napi_make_callback.c @@ -0,0 +1,56 @@ +#include +#include "common.h" + +#define MAX_ARGUMENTS 10 + +static napi_value MakeCallback(napi_env env, napi_callback_info info) { + size_t argc = MAX_ARGUMENTS; + size_t n; + napi_value args[MAX_ARGUMENTS]; + // NOLINTNEXTLINE (readability/null_usage) + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + NAPI_ASSERT(env, argc > 0, "Wrong number of arguments"); + + napi_value recv = args[0]; + napi_value func = args[1]; + + napi_value argv[MAX_ARGUMENTS - 2]; + for (n = 2; n < argc; n += 1) { + argv[n - 2] = args[n]; + } + + napi_valuetype func_type; + + NAPI_CALL(env, napi_typeof(env, func, &func_type)); + + napi_value resource_name; + NAPI_CALL(env, napi_create_string_utf8(env, "test", NAPI_AUTO_LENGTH, + &resource_name)); + + napi_async_context context; + NAPI_CALL(env, napi_async_init(env, func, resource_name, &context)); + + napi_value result; + if (func_type == napi_function) { + NAPI_CALL(env, napi_make_callback(env, context, recv, func, argc - 2, argv, + &result)); + } else { + NAPI_ASSERT(env, false, "Unexpected argument type"); + } + + NAPI_CALL(env, napi_async_destroy(env, context)); + + return result; +} + +static napi_value Init(napi_env env, napi_value exports) { + napi_value fn; + NAPI_CALL(env, napi_create_function( + // NOLINTNEXTLINE (readability/null_usage) + env, NULL, NAPI_AUTO_LENGTH, MakeCallback, NULL, &fn)); + NAPI_CALL(env, napi_set_named_property(env, exports, "makeCallback", fn)); + return exports; +} + +NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) diff --git a/test/napi/test_napi_make_callback.js b/test/napi/test_napi_make_callback.js new file mode 100644 index 0000000000..f16354c726 --- /dev/null +++ b/test/napi/test_napi_make_callback.js @@ -0,0 +1,31 @@ +'use strict'; + +var common = require('common.js'); +var assert = require('assert'); +var binding = require('./build/' + common.buildTypePath + + '/test_napi_make_callback.node'); +var makeCallback = binding.makeCallback; + +function myMultiArgFunc(arg1, arg2, arg3) { + assert.strictEqual(arg1, 1); + assert.strictEqual(arg2, 2); + assert.strictEqual(arg3, 3); + return 42; +} + +assert.strictEqual(42, makeCallback(process, common.mustCall(function() { + assert.strictEqual(0, arguments.length); + assert.strictEqual(this, process); + return 42; +}))); + +assert.strictEqual(42, makeCallback(process, common.mustCall(function(x) { + assert.strictEqual(1, arguments.length); + assert.strictEqual(this, process); + assert.strictEqual(x, 1337); + return 42; +}), 1337)); + +assert.strictEqual(42, + makeCallback(this, + common.mustCall(myMultiArgFunc), 1, 2, 3)); diff --git a/test/napi/test_napi_make_callback_error.js b/test/napi/test_napi_make_callback_error.js new file mode 100644 index 0000000000..204c242e35 --- /dev/null +++ b/test/napi/test_napi_make_callback_error.js @@ -0,0 +1,24 @@ +'use strict'; + +var common = require('common.js'); +var assert = require('assert'); +var binding = require('./build/' + common.buildTypePath + + '/test_napi_make_callback.node'); +var makeCallback = binding.makeCallback; + +var first = true; +process.on('uncaughtException', function(err) { + if (first) { + assert.strictEqual(err.message, 'foobar'); + first = false; + return; + } + assert.strictEqual(err.message, 'tick'); +}); + +process.nextTick(common.mustCall(function() { + throw new Error('tick'); +})); +makeCallback(process, common.mustCall(function() { + throw new Error('foobar'); +})); diff --git a/test/napi/test_napi_object_wrap.c b/test/napi/test_napi_object_wrap.c new file mode 100644 index 0000000000..e32d3cb0cc --- /dev/null +++ b/test/napi/test_napi_object_wrap.c @@ -0,0 +1,51 @@ +#include +#include +#include "common.h" + +static size_t native_counter = 0; +static size_t native_hint = 0x8888; +static napi_ref weak_ref; + +static void finalize(napi_env env, void* finalize_data, void* finalize_hint) { + size_t* f_data = (size_t*)finalize_data; + size_t* f_hint = (size_t*)finalize_hint; + if (*f_hint != native_hint) + napi_fatal_error(__FILE__, NAPI_AUTO_LENGTH, "finalize hint not aligned.", + NAPI_AUTO_LENGTH); + *f_data += 1; + napi_delete_reference(env, weak_ref); +} + +static void cleanup(void* data) { + if (native_counter == 0) { + napi_fatal_error(__FILE__, NAPI_AUTO_LENGTH, "finalize not invoked.", + NAPI_AUTO_LENGTH); + } +} + +napi_value wrap(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value argv[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); + + NAPI_CALL(env, napi_wrap(env, argv[0], &native_counter, finalize, + &native_hint, &weak_ref)); + /** + * `weak_ref` is a weak reference, so leave as it be. + */ + return argv[0]; +} + +napi_value get_native_counter(napi_env env, napi_callback_info info) { + napi_value count; + NAPI_CALL(env, napi_create_uint32(env, native_counter, &count)); + return count; +} + +NAPI_MODULE_INIT() { + SET_NAMED_METHOD(env, exports, "Wrap", wrap); + SET_NAMED_METHOD(env, exports, "GetNativeCounter", get_native_counter); + + NAPI_CALL(env, napi_add_env_cleanup_hook(env, cleanup, NULL)); + return exports; +} diff --git a/test/napi/test_napi_object_wrap.js b/test/napi/test_napi_object_wrap.js new file mode 100644 index 0000000000..55ba6d61f7 --- /dev/null +++ b/test/napi/test_napi_object_wrap.js @@ -0,0 +1,16 @@ + +'use strict'; +var assert = require('assert'); +var common = require('common.js'); +var test = require('./build/' + common.buildTypePath + + '/test_napi_object_wrap.node'); + +function context() { + var obj = {}; + assert.strictEqual(test.Wrap(obj), obj); +} + +assert.strictEqual(test.GetNativeCounter(), 0); +context(); +process.gc(); +assert.strictEqual(test.GetNativeCounter(), 1); diff --git a/test/napi/test_napi_promise.c b/test/napi/test_napi_promise.c new file mode 100644 index 0000000000..8275536116 --- /dev/null +++ b/test/napi/test_napi_promise.c @@ -0,0 +1,64 @@ +#include +#include "common.h" + +napi_deferred deferred = NULL; + +static napi_value createPromise(napi_env env, napi_callback_info info) { + napi_value promise; + + // We do not overwrite an existing deferred. + if (deferred != NULL) { + return NULL; + } + + NAPI_CALL(env, napi_create_promise(env, &deferred, &promise)); + + return promise; +} + +static napi_value concludeCurrentPromise(napi_env env, + napi_callback_info info) { + napi_value argv[2]; + size_t argc = 2; + bool resolution; + + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); + NAPI_CALL(env, napi_get_value_bool(env, argv[1], &resolution)); + if (resolution) { + NAPI_CALL(env, napi_resolve_deferred(env, deferred, argv[0])); + } else { + NAPI_CALL(env, napi_reject_deferred(env, deferred, argv[0])); + } + + deferred = NULL; + + return NULL; +} + +static napi_value isPromise(napi_env env, napi_callback_info info) { + napi_value promise, result; + size_t argc = 1; + bool is_promise; + + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &promise, NULL, NULL)); + NAPI_CALL(env, napi_is_promise(env, promise, &is_promise)); + NAPI_CALL(env, napi_get_boolean(env, is_promise, &result)); + + return result; +} + +static napi_value Init(napi_env env, napi_value exports) { + napi_property_descriptor descriptors[] = { + DECLARE_NAPI_PROPERTY("createPromise", createPromise), + DECLARE_NAPI_PROPERTY("concludeCurrentPromise", concludeCurrentPromise), + DECLARE_NAPI_PROPERTY("isPromise", isPromise), + }; + + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(descriptors) / + sizeof(*descriptors), + descriptors)); + + return exports; +} + +NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) diff --git a/test/napi/test_napi_promise.js b/test/napi/test_napi_promise.js new file mode 100644 index 0000000000..331a3a31c1 --- /dev/null +++ b/test/napi/test_napi_promise.js @@ -0,0 +1,59 @@ +'use strict'; + +var common = require('common.js'); + +// This tests the promise-related n-api calls + +var assert = require('assert'); +var test_promise = require('./build/' + common.buildTypePath + + '/test_napi_promise.node'); + +// A resolution +{ + var expected_result = 42; + var promise = test_promise.createPromise(); + promise.then( + common.mustCall(function(result) { + assert.strictEqual(result, expected_result); + })); + test_promise.concludeCurrentPromise(expected_result, true); +} + +// A rejection +{ + var expected_result = 'It\'s not you, it\'s me.'; + var promise = test_promise.createPromise(); + promise.then(function(result) { + // This should never be called + assert.strictEqual(true, false); + }); + test_promise.concludeCurrentPromise(expected_result, false); +} + +// Chaining +{ + var expected_result = 'chained answer'; + var promise = test_promise.createPromise(); + promise.then( + common.mustCall(function(result) { + assert.strictEqual(result, expected_result); + })); + test_promise.concludeCurrentPromise(Promise.resolve('chained answer'), true); +} + +var promiseTypeTestPromise = test_promise.createPromise(); +assert.strictEqual(test_promise.isPromise(promiseTypeTestPromise), true); +test_promise.concludeCurrentPromise(undefined, true); + +var rejectPromise = Promise.reject(-1); +var expected_reason = -1; +assert.strictEqual(test_promise.isPromise(rejectPromise), true); +rejectPromise.catch((reason) => { + assert.strictEqual(reason, expected_reason); +}); + +assert.strictEqual(test_promise.isPromise(2.4), false); +assert.strictEqual(test_promise.isPromise('I promise!'), false); +assert.strictEqual(test_promise.isPromise(undefined), false); +assert.strictEqual(test_promise.isPromise(null), false); +assert.strictEqual(test_promise.isPromise({}), false); diff --git a/test/napi/test_napi_properties.c b/test/napi/test_napi_properties.c new file mode 100644 index 0000000000..4d589b53a9 --- /dev/null +++ b/test/napi/test_napi_properties.c @@ -0,0 +1,189 @@ +/* Copyright 2019-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 "common.h" +#include "node_api.h" + +static napi_value get_property(napi_env env, napi_callback_info info) { + size_t argc = 2; + napi_value args[2]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + NAPI_ASSERT(env, argc >= 2, "Wrong number of arguments"); + + napi_valuetype valuetype0; + NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0)); + + NAPI_ASSERT(env, valuetype0 == napi_object, + "Wrong type of arguments. Expects an object as first argument."); + + napi_valuetype valuetype1; + NAPI_CALL(env, napi_typeof(env, args[1], &valuetype1)); + + NAPI_ASSERT(env, valuetype1 == napi_string, + "Wrong type of arguments. Expects a string as second argument."); + + napi_value object = args[0]; + napi_value output; + NAPI_CALL(env, napi_get_property(env, object, args[1], &output)); + + return output; +} + +static napi_value set_property(napi_env env, napi_callback_info info) { + size_t argc = 3; + napi_value args[3]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + NAPI_ASSERT(env, argc >= 3, "Wrong number of arguments"); + + napi_valuetype valuetype0; + NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0)); + + NAPI_ASSERT(env, valuetype0 == napi_object, + "Wrong type of arguments. Expects an object as first argument."); + + napi_valuetype valuetype1; + NAPI_CALL(env, napi_typeof(env, args[1], &valuetype1)); + + NAPI_ASSERT(env, valuetype1 == napi_string, + "Wrong type of arguments. Expects a string as second argument."); + + NAPI_CALL(env, napi_set_property(env, args[0], args[1], args[2])); + + napi_value valuetrue; + NAPI_CALL(env, napi_get_boolean(env, true, &valuetrue)); + + return valuetrue; +} + +static napi_value has_property(napi_env env, napi_callback_info info) { + size_t argc = 2; + napi_value args[2]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + NAPI_ASSERT(env, argc >= 2, "Wrong number of arguments"); + + napi_valuetype valuetype0; + NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0)); + + NAPI_ASSERT(env, valuetype0 == napi_object, + "Wrong type of arguments. Expects an object as first argument."); + + napi_valuetype valuetype1; + NAPI_CALL(env, napi_typeof(env, args[1], &valuetype1)); + + NAPI_ASSERT(env, valuetype1 == napi_string, + "Wrong type of arguments. Expects a string as second argument."); + + bool has_property; + NAPI_CALL(env, napi_has_property(env, args[0], args[1], &has_property)); + + napi_value ret; + NAPI_CALL(env, napi_get_boolean(env, has_property, &ret)); + + return ret; +} + +static napi_value has_own_property(napi_env env, napi_callback_info info) { + size_t argc = 2; + napi_value args[2]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + NAPI_ASSERT(env, argc == 2, "Wrong number of arguments"); + + napi_valuetype valuetype0; + NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0)); + + NAPI_ASSERT(env, valuetype0 == napi_object, + "Wrong type of arguments. Expects an object as first argument."); + + napi_valuetype valuetype1; + NAPI_CALL(env, napi_typeof(env, args[1], &valuetype1)); + + NAPI_ASSERT(env, valuetype1 == napi_string, + "Wrong type of arguments. Expects a string as second argument."); + + bool has_property; + NAPI_CALL(env, napi_has_own_property(env, args[0], args[1], &has_property)); + + napi_value ret; + NAPI_CALL(env, napi_get_boolean(env, has_property, &ret)); + + return ret; +} + +static napi_value get_property_names(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + NAPI_ASSERT(env, argc >= 1, "Wrong number of arguments"); + + napi_valuetype valuetype0; + NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0)); + + NAPI_ASSERT(env, valuetype0 == napi_object, + "Wrong type of arguments. Expects an object as first argument."); + + napi_value obj = args[0]; + napi_value propertynames; + NAPI_CALL(env, napi_get_property_names(env, obj, &propertynames)); + return propertynames; +} + +static napi_value delete_property(napi_env env, napi_callback_info info) { + size_t argc = 2; + napi_value args[2]; + + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + NAPI_ASSERT(env, argc == 2, "Wrong number of arguments"); + + napi_valuetype valuetype0; + NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0)); + NAPI_ASSERT(env, valuetype0 == napi_object, + "Wrong type of arguments. Expects an object as first argument."); + + napi_valuetype valuetype1; + NAPI_CALL(env, napi_typeof(env, args[1], &valuetype1)); + NAPI_ASSERT(env, valuetype1 == napi_string, + "Wrong type of arguments. Expects a string as second argument."); + + bool result; + napi_value ret; + NAPI_CALL(env, napi_delete_property(env, args[0], args[1], &result)); + NAPI_CALL(env, napi_get_boolean(env, result, &ret)); + + return ret; +} + +static napi_value init(napi_env env, napi_value exports) { + napi_property_descriptor descriptors[] = { + DECLARE_NAPI_PROPERTY("GetProperty", get_property), + DECLARE_NAPI_PROPERTY("SetProperty", set_property), + DECLARE_NAPI_PROPERTY("HasProperty", has_property), + DECLARE_NAPI_PROPERTY("HasOwnProperty", has_own_property), + DECLARE_NAPI_PROPERTY("GetNames", get_property_names), + DECLARE_NAPI_PROPERTY("DeleteProperty", delete_property), + }; + + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(descriptors) / + sizeof(*descriptors), + descriptors)); + + return exports; +} + +NAPI_MODULE(NODE_GYP_MODULE_NAME, init) diff --git a/test/napi/test_napi_properties.js b/test/napi/test_napi_properties.js new file mode 100644 index 0000000000..afa97a9066 --- /dev/null +++ b/test/napi/test_napi_properties.js @@ -0,0 +1,78 @@ +/* Copyright 2019-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 common = require('common.js'); + +var prop_module = require('./build/' + common.buildTypePath + + '/test_napi_properties.node'); + +var obj = { + array: [ + 1, 94, 'str', 12.321, { test: 'obj in arr' } + ], + num: 123, + subObj: { + test: 'obj in obj' + }, + str: 'hello' +}; + +var names = prop_module.GetNames(obj); +var keys = Object.keys(obj); +assert.strictEqual(names.length, keys.length); +for (var i = 0; i < keys.length; i++) { + assert(prop_module.HasProperty(obj, keys[i])); + assert.strictEqual(names[i], keys[i]); +} + +assert.strictEqual(prop_module.GetProperty(obj, 'unkown'), undefined); +assert(!prop_module.HasProperty(obj, 'unkown')); +assert.strictEqual(prop_module.GetProperty(obj, 'num'), 123); +assert(prop_module.SetProperty(obj, 'num', 321)); +assert.strictEqual(prop_module.GetProperty(obj, 'num'), 321); +assert.strictEqual(prop_module.GetProperty(obj, 'str'), 'hello'); + +assert(!prop_module.HasProperty(obj, 'newProp')); +assert(prop_module.SetProperty(obj, 'newProp', 'newValue')); +assert(prop_module.HasProperty(obj, 'newProp')); +assert.strictEqual(prop_module.GetProperty(obj, 'newProp'), 'newValue'); + +assert(prop_module.DeleteProperty(obj, 'newProp')); +assert(!prop_module.HasProperty(obj, 'newProp')); + +/* Test prototype chain */ +function Person(first, last, age, eyecolor) { + this.firstName = first; + this.lastName = last; +} + +Person.prototype.name = function() { + return this.firstName + " " + this.lastName; +}; + +var person = new Person('John', 'Doe', 99, 'blue'); + +assert(prop_module.HasProperty(person, 'name')); +assert(prop_module.HasProperty(person, 'firstName')); +assert(prop_module.HasProperty(person, 'lastName')); +assert(!prop_module.HasOwnProperty(person, 'name')); +assert(prop_module.HasOwnProperty(person, 'firstName')); +assert(prop_module.HasOwnProperty(person, 'lastName')); + +assert(prop_module.DeleteProperty(Person.prototype, 'name')); +assert(!prop_module.HasProperty(person, 'name')); +assert(prop_module.HasProperty(person, 'firstName')); +assert(prop_module.HasProperty(person, 'lastName')); diff --git a/test/napi/test_napi_reference.c b/test/napi/test_napi_reference.c new file mode 100644 index 0000000000..88cf9661a1 --- /dev/null +++ b/test/napi/test_napi_reference.c @@ -0,0 +1,149 @@ +#include "common.h" +#include "node_api.h" + +static int test_value = 1; +static int finalize_count = 0; +static napi_ref test_reference = NULL; + +static napi_value get_finalize_count(napi_env env, napi_callback_info info) { + napi_value result; + NAPI_CALL(env, napi_create_int32(env, finalize_count, &result)); + return result; +} + +static void finalize_external(napi_env env, void* data, void* hint) { + int* actual_value = data; + NAPI_ASSERT_RETURN_VOID(env, actual_value == &test_value, + "The correct pointer was passed to the finalizer"); + finalize_count++; +} + +static napi_value create_external(napi_env env, napi_callback_info info) { + int* data = &test_value; + + napi_value result; + NAPI_CALL(env, napi_create_external(env, data, NULL, /* finalize_cb */ + NULL, /* finalize_hint */ + &result)); + + finalize_count = 0; + return result; +} + +static napi_value create_external_with_finalize(napi_env env, + napi_callback_info info) { + napi_value result; + NAPI_CALL(env, napi_create_external(env, &test_value, finalize_external, + NULL, /* finalize_hint */ + &result)); + + finalize_count = 0; + return result; +} + +static napi_value check_external(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value arg; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &arg, NULL, NULL)); + + NAPI_ASSERT(env, argc == 1, "Expected one argument."); + + napi_valuetype argtype; + NAPI_CALL(env, napi_typeof(env, arg, &argtype)); + + NAPI_ASSERT(env, argtype == napi_external, "Expected an external value."); + + void* data; + NAPI_CALL(env, napi_get_value_external(env, arg, &data)); + + NAPI_ASSERT(env, data != NULL && *(int*)data == test_value, + "An external data value of 1 was expected."); + + return NULL; +} + +static napi_value create_reference(napi_env env, napi_callback_info info) { + NAPI_ASSERT(env, test_reference == NULL, + "The test allows only one reference at a time."); + + size_t argc = 2; + napi_value args[2]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + NAPI_ASSERT(env, argc == 2, "Expected two arguments."); + + uint32_t initial_refcount; + NAPI_CALL(env, napi_get_value_uint32(env, args[1], &initial_refcount)); + + NAPI_CALL(env, napi_create_reference(env, args[0], initial_refcount, + &test_reference)); + + NAPI_ASSERT(env, test_reference != NULL, + "A reference should have been created."); + + return NULL; +} + +static napi_value delete_reference(napi_env env, napi_callback_info info) { + NAPI_ASSERT(env, test_reference != NULL, + "A reference must have been created."); + + NAPI_CALL(env, napi_delete_reference(env, test_reference)); + test_reference = NULL; + return NULL; +} + +static napi_value increment_refcount(napi_env env, napi_callback_info info) { + NAPI_ASSERT(env, test_reference != NULL, + "A reference must have been created."); + + uint32_t refcount; + NAPI_CALL(env, napi_reference_ref(env, test_reference, &refcount)); + + napi_value result; + NAPI_CALL(env, napi_create_uint32(env, refcount, &result)); + return result; +} + +static napi_value decrement_refcount(napi_env env, napi_callback_info info) { + NAPI_ASSERT(env, test_reference != NULL, + "A reference must have been created."); + + uint32_t refcount; + NAPI_CALL(env, napi_reference_unref(env, test_reference, &refcount)); + + napi_value result; + NAPI_CALL(env, napi_create_uint32(env, refcount, &result)); + return result; +} + +static napi_value get_reference_value(napi_env env, napi_callback_info info) { + NAPI_ASSERT(env, test_reference != NULL, + "A reference must have been created."); + + napi_value result; + NAPI_CALL(env, napi_get_reference_value(env, test_reference, &result)); + return result; +} + +static napi_value init(napi_env env, napi_value exports) { + napi_property_descriptor descriptors[] = { + DECLARE_NAPI_GETTER("finalizeCount", get_finalize_count), + DECLARE_NAPI_PROPERTY("createExternal", create_external), + DECLARE_NAPI_PROPERTY("createExternalWithFinalize", + create_external_with_finalize), + DECLARE_NAPI_PROPERTY("checkExternal", check_external), + DECLARE_NAPI_PROPERTY("createReference", create_reference), + DECLARE_NAPI_PROPERTY("deleteReference", delete_reference), + DECLARE_NAPI_PROPERTY("incrementRefcount", increment_refcount), + DECLARE_NAPI_PROPERTY("decrementRefcount", decrement_refcount), + DECLARE_NAPI_GETTER("referenceValue", get_reference_value), + }; + + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(descriptors) / + sizeof(*descriptors), + descriptors)); + + return exports; +} + +NAPI_MODULE(NODE_GYP_MODULE_NAME, init) diff --git a/test/napi/test_napi_reference.js b/test/napi/test_napi_reference.js new file mode 100644 index 0000000000..4ee305a3d4 --- /dev/null +++ b/test/napi/test_napi_reference.js @@ -0,0 +1,121 @@ +'use strict'; +// Flags: --expose-gc + +var assert = require('assert'); +var common = require('common.js'); + +var test_reference = require('./build/' + common.buildTypePath + + '/test_napi_reference.node'); + +// This test script uses external values with finalizer callbacks +// in order to track when values get garbage-collected. Each invocation +// of a finalizer callback increments the finalizeCount property. +assert.strictEqual(test_reference.finalizeCount, 0); + +// Run each test function in sequence, +// with an async delay and GC call between each. +function runTests(i, title, tests) { + if (tests[i]) { + if (typeof tests[i] === 'string') { + title = tests[i]; + runTests(i + 1, title, tests); + } else { + try { + tests[i](); + } catch (e) { + console.error('Test failed: ' + title); + throw e; + } + setImmediate(function() { + process.gc(); + runTests(i + 1, title, tests); + }); + } + } +} +runTests(0, undefined, [ + + 'External value without a finalizer', + function() { + var value = test_reference.createExternal(); + assert.strictEqual(test_reference.finalizeCount, 0); + assert.strictEqual(typeof value, 'object'); + test_reference.checkExternal(value); + }, + function() { + assert.strictEqual(test_reference.finalizeCount, 0); + }, + + 'External value with a finalizer', + function() { + var value = test_reference.createExternalWithFinalize(); + assert.strictEqual(test_reference.finalizeCount, 0); + assert.strictEqual(typeof value, 'object'); + test_reference.checkExternal(value); + }, + function() { + assert.strictEqual(test_reference.finalizeCount, 1); + }, + + 'Weak reference', + function() { + var value = test_reference.createExternalWithFinalize(); + assert.strictEqual(test_reference.finalizeCount, 0); + test_reference.createReference(value, 0); + assert.strictEqual(test_reference.referenceValue, value); + }, + function() { + // Value should be GC'd because there is only a weak ref + assert.strictEqual(test_reference.referenceValue, undefined); + assert.strictEqual(test_reference.finalizeCount, 1); + test_reference.deleteReference(); + }, + + 'Strong reference', + function() { + var value = test_reference.createExternalWithFinalize(); + assert.strictEqual(test_reference.finalizeCount, 0); + test_reference.createReference(value, 1); + assert.strictEqual(test_reference.referenceValue, value); + }, + function() { + // Value should NOT be GC'd because there is a strong ref + assert.strictEqual(test_reference.finalizeCount, 0); + test_reference.deleteReference(); + }, + function() { + // Value should be GC'd because the strong ref was deleted + assert.strictEqual(test_reference.finalizeCount, 1); + }, + + 'Strong reference, increment then decrement to weak reference', + function() { + var value = test_reference.createExternalWithFinalize(); + assert.strictEqual(test_reference.finalizeCount, 0); + test_reference.createReference(value, 1); + }, + function() { + // Value should NOT be GC'd because there is a strong ref + assert.strictEqual(test_reference.finalizeCount, 0); + assert.strictEqual(test_reference.incrementRefcount(), 2); + }, + function() { + // Value should NOT be GC'd because there is a strong ref + assert.strictEqual(test_reference.finalizeCount, 0); + assert.strictEqual(test_reference.decrementRefcount(), 1); + }, + function() { + // Value should NOT be GC'd because there is a strong ref + assert.strictEqual(test_reference.finalizeCount, 0); + assert.strictEqual(test_reference.decrementRefcount(), 0); + }, + function() { + // Value should be GC'd because the ref is now weak! + assert.strictEqual(test_reference.finalizeCount, 1); + test_reference.deleteReference(); + }, + function() { + // Value was already GC'd + assert.strictEqual(test_reference.finalizeCount, 1); + }, +]); diff --git a/test/napi/test_napi_strictequal_and_instanceof.c b/test/napi/test_napi_strictequal_and_instanceof.c new file mode 100644 index 0000000000..f7f6ad2a7e --- /dev/null +++ b/test/napi/test_napi_strictequal_and_instanceof.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include "common.h" + +napi_value SayHello(napi_env env, napi_callback_info info) { + size_t argc = 0; + // test if `napi_get_cb_info` tolerants NULL pointers. + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, NULL, NULL, NULL)); + + napi_value str; + NAPI_CALL(env, napi_create_string_utf8(env, "Hello", 5, &str)); + + return str; +} + +napi_value SayError(napi_env env, napi_callback_info info) { + NAPI_CALL(env, napi_throw_error(env, "foo", "bar")); + + return NULL; +} + +napi_value StrictEquals(napi_env env, napi_callback_info info) { + size_t argc = 2; + napi_value argv[2]; + napi_value thisArg; + void* data; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, &data)); + + bool result = false; + NAPI_CALL(env, napi_strict_equals(env, argv[0], argv[1], &result)); + + napi_value ret; + NAPI_CALL(env, napi_get_boolean(env, result, &ret)); + + return ret; +} + +napi_value Instanceof(napi_env env, napi_callback_info info) { + size_t argc = 2; + napi_value argv[2]; + napi_value thisArg; + void* data; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, &data)); + + bool result = false; + NAPI_CALL(env, napi_instanceof(env, argv[0], argv[1], &result)); + + napi_value ret; + NAPI_CALL(env, napi_get_boolean(env, result, &ret)); + + return ret; +} + +napi_value Init(napi_env env, napi_value exports) { + SET_NAMED_METHOD(env, exports, "sayHello", SayHello); + SET_NAMED_METHOD(env, exports, "sayError", SayError); + SET_NAMED_METHOD(env, exports, "strictEquals", StrictEquals); + SET_NAMED_METHOD(env, exports, "instanceof", Instanceof); + + napi_value id; + NAPI_CALL(env, napi_create_int32(env, 321, &id)); + NAPI_CALL(env, napi_set_named_property(env, exports, "id", id)); + + return exports; +} + +NAPI_MODULE(napi_test, Init); diff --git a/test/napi/test_napi_strictequal_and_instanceof.js b/test/napi/test_napi_strictequal_and_instanceof.js new file mode 100644 index 0000000000..c7634b442c --- /dev/null +++ b/test/napi/test_napi_strictequal_and_instanceof.js @@ -0,0 +1,29 @@ +'use strict'; +var assert = require('assert'); +var common = require('common.js'); +var napi_test = + require('./build/' + common.buildTypePath + + '/test_napi_strictequal_and_instanceof.node'); + +assert(napi_test !== null); +assert.strictEqual(typeof napi_test, 'object'); +assert.strictEqual(napi_test.id, 321); + +assert.strictEqual(typeof napi_test.sayHello, 'function'); +assert.strictEqual(napi_test.sayHello(), 'Hello'); + +assert.strictEqual(typeof napi_test.sayError, 'function'); + +var error; +try { + napi_test.sayError(); +} catch (err) { + error = err; +} +assert(error instanceof Error); +assert.strictEqual(error.code, 'foo'); +assert.strictEqual(error.message, 'bar'); + +var lhs = {}; +assert.strictEqual(napi_test.strictEquals(lhs, lhs), true); +assert.strictEqual(napi_test.instanceof(lhs, Object), lhs instanceof Object); diff --git a/test/napi/test_napi_string.c b/test/napi/test_napi_string.c new file mode 100644 index 0000000000..9d0c6076c8 --- /dev/null +++ b/test/napi/test_napi_string.c @@ -0,0 +1,89 @@ +#include +#include +#include +#include "common.h" + +static napi_value TestUtf8(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + NAPI_ASSERT(env, argc >= 1, "Wrong number of arguments"); + + napi_valuetype valuetype; + NAPI_CALL(env, napi_typeof(env, args[0], &valuetype)); + + NAPI_ASSERT(env, valuetype == napi_string, + "Wrong type of argment. Expects a string."); + + char buffer[128]; + size_t buffer_size = 128; + size_t copied; + + NAPI_CALL(env, napi_get_value_string_utf8(env, args[0], buffer, buffer_size, + &copied)); + + napi_value output; + NAPI_CALL(env, napi_create_string_utf8(env, buffer, copied, &output)); + + return output; +} + + +static napi_value TestUtf8Insufficient(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + NAPI_ASSERT(env, argc >= 1, "Wrong number of arguments"); + + napi_valuetype valuetype; + NAPI_CALL(env, napi_typeof(env, args[0], &valuetype)); + + NAPI_ASSERT(env, valuetype == napi_string, + "Wrong type of argment. Expects a string."); + + char buffer[4]; + size_t buffer_size = 4; + size_t copied; + + NAPI_CALL(env, napi_get_value_string_utf8(env, args[0], buffer, buffer_size, + &copied)); + + napi_value output; + NAPI_CALL(env, napi_create_string_utf8(env, buffer, copied, &output)); + + return output; +} + +static napi_value Utf8Length(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + NAPI_ASSERT(env, argc >= 1, "Wrong number of arguments"); + + napi_valuetype valuetype; + NAPI_CALL(env, napi_typeof(env, args[0], &valuetype)); + + NAPI_ASSERT(env, valuetype == napi_string, + "Wrong type of argment. Expects a string."); + + size_t length; + NAPI_CALL(env, napi_get_value_string_utf8(env, args[0], NULL, 0, &length)); + + napi_value output; + NAPI_CALL(env, napi_create_uint32(env, (uint32_t)length, &output)); + + return output; +} + +napi_value Init(napi_env env, napi_value exports) { + SET_NAMED_METHOD(env, exports, "TestUtf8", TestUtf8); + SET_NAMED_METHOD(env, exports, "TestUtf8Insufficient", TestUtf8Insufficient); + SET_NAMED_METHOD(env, exports, "Utf8Length", Utf8Length); + + return exports; +} + +NAPI_MODULE(napi_test, Init); diff --git a/test/napi/test_napi_string.js b/test/napi/test_napi_string.js new file mode 100644 index 0000000000..a85294b593 --- /dev/null +++ b/test/napi/test_napi_string.js @@ -0,0 +1,32 @@ +'use strict'; +var assert = require('assert'); +var common = require('common.js'); +var test = require('./build/' + common.buildTypePath + + '/test_napi_string.node'); + +var empty = ''; +assert.strictEqual(test.TestUtf8(empty), empty); +assert.strictEqual(test.Utf8Length(empty), 0); + +var str1 = 'hello world'; +assert.strictEqual(test.TestUtf8(str1), str1); +assert.strictEqual(test.Utf8Length(str1), 11); + +var str2 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; +assert.strictEqual(test.TestUtf8(str2), str2); +assert.strictEqual(test.Utf8Length(str2), 62); + +var str3 = '?!@#$%^&*()_+-=[]{}/.,<>\'"\\'; +assert.strictEqual(test.TestUtf8(str3), str3); +assert.strictEqual(test.Utf8Length(str3), 27); + +var str4 = '¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿'; +assert.strictEqual(test.TestUtf8(str4), str4); +assert.strictEqual(test.Utf8Length(str4), 62); + +var str5 ='ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞ' + + 'ßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþ'; +assert.strictEqual(test.TestUtf8(str5), str5); +assert.strictEqual(test.Utf8Length(str5), 126); + +// TODO: jerry-script doesn't support copy string value to insufficient buf diff --git a/test/napi/test_napi_symbol.c b/test/napi/test_napi_symbol.c new file mode 100644 index 0000000000..58a91cb7e2 --- /dev/null +++ b/test/napi/test_napi_symbol.c @@ -0,0 +1,38 @@ +#include "common.h" +#include "node_api.h" + +static napi_value create_symbol(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + napi_value description = NULL; + if (argc >= 1) { + napi_valuetype valuetype; + NAPI_CALL(env, napi_typeof(env, args[0], &valuetype)); + + NAPI_ASSERT(env, valuetype == napi_string, + "Wrong type of arguments. Expects a string."); + + description = args[0]; + } + + napi_value symbol; + NAPI_CALL(env, napi_create_symbol(env, description, &symbol)); + + return symbol; +} + +static napi_value Init(napi_env env, napi_value exports) { + napi_property_descriptor properties[] = { + DECLARE_NAPI_PROPERTY("CreateSymbol", create_symbol), + }; + + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(properties) / + sizeof(*properties), + properties)); + + return exports; +} + +NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) diff --git a/test/napi/test_napi_symbol.js b/test/napi/test_napi_symbol.js new file mode 100644 index 0000000000..4cbf7c4abd --- /dev/null +++ b/test/napi/test_napi_symbol.js @@ -0,0 +1,50 @@ +'use strict'; +var assert = require('assert'); +var common = require('common.js'); + +// testing api calls for symbol +var test_symbol = require('./build/' + common.buildTypePath + + '/test_napi_symbol.node'); + +var sym = test_symbol.CreateSymbol('test'); +assert.strictEqual(sym.toString(), 'Symbol(test)'); + +{ + var myObj = {}; + var fooSym = test_symbol.CreateSymbol('foo'); + var otherSym = test_symbol.CreateSymbol('bar'); + myObj.foo = 'bar'; + myObj[fooSym] = 'baz'; + myObj[otherSym] = 'bing'; + assert.strictEqual(myObj.foo, 'bar'); + assert.strictEqual(myObj[fooSym], 'baz'); + assert.strictEqual(myObj[otherSym], 'bing'); +} + +{ + var fooSym = test_symbol.CreateSymbol('foo'); + var myObj = {}; + myObj.foo = 'bar'; + myObj[fooSym] = 'baz'; + Object.keys(myObj); // -> [ 'foo' ] + Object.getOwnPropertyNames(myObj); // -> [ 'foo' ] + Object.getOwnPropertySymbols(myObj); // -> [ Symbol(foo) ] + assert.strictEqual(Object.getOwnPropertySymbols(myObj)[0], fooSym); +} + +{ + assert.notStrictEqual(test_symbol.CreateSymbol(), test_symbol.CreateSymbol()); + assert.notStrictEqual(test_symbol.CreateSymbol('foo'), + test_symbol.CreateSymbol('foo')); + assert.notStrictEqual(test_symbol.CreateSymbol('foo'), + test_symbol.CreateSymbol('bar')); + + var foo1 = test_symbol.CreateSymbol('foo'); + var foo2 = test_symbol.CreateSymbol('foo'); + var object = { + [foo1]: 1, + [foo2]: 2, + }; + assert.strictEqual(object[foo1], 1); + assert.strictEqual(object[foo2], 2); +} diff --git a/test/napi/test_napi_throw.js b/test/napi/test_napi_throw.js new file mode 100644 index 0000000000..35d9a13bb6 --- /dev/null +++ b/test/napi/test_napi_throw.js @@ -0,0 +1,26 @@ +var common = require('common.js'); +var addon = require('./build/' + common.buildTypePath + + '/test_napi_error_handling'); +var assert = require('assert'); + +var ERROR_MSG = "ErrorMSG"; +var error = new Error(ERROR_MSG); +var catched; + +try { + addon.Throw(error) +} catch (e) { + catched = e; +} + +assert(catched instanceof Error) +assert(catched.message === ERROR_MSG) + +try { + addon.Throw(ERROR_MSG) +} catch (e) { + catched = e; +} + +assert(typeof catched === 'string') +assert(catched === ERROR_MSG) diff --git a/test/napi/test_napi_throw_error.js b/test/napi/test_napi_throw_error.js new file mode 100644 index 0000000000..0abc00d463 --- /dev/null +++ b/test/napi/test_napi_throw_error.js @@ -0,0 +1,40 @@ +var common = require('common.js'); +var addon = require('./build/' + common.buildTypePath + + '/test_napi_error_handling'); +var assert = require('assert'); + +var error; +var ERROR_CODE = "ErrorCODE"; +var ERROR_MSG = "ErrorMSG"; + +// Error +try { + addon.ThrowError(); +} catch (e) { + error = e; +} + +assert(error instanceof Error); +assert(error.code === "ErrorCODE"); +assert(error.message === "ErrorMSG"); + +//TypeError +try { + addon.ThrowTypeError(); +} catch (e) { + error = e; +} + +assert(error instanceof TypeError); +assert(error.code === "ErrorCODE"); +assert(error.message === "ErrorMSG"); + +//RangeError +try { + addon.ThrowRangeError(); +} catch (e) { + error = e; +} +assert(error instanceof RangeError); +assert(error.code === "ErrorCODE"); +assert(error.message === "ErrorMSG"); diff --git a/test/napi/test_napi_typedarray.c b/test/napi/test_napi_typedarray.c new file mode 100644 index 0000000000..6633d160e9 --- /dev/null +++ b/test/napi/test_napi_typedarray.c @@ -0,0 +1,185 @@ +#include "common.h" +#include "node_api.h" + +#include + +static napi_value multiply(napi_env env, napi_callback_info info) { + size_t argc = 2; + napi_value args[2]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + NAPI_ASSERT(env, argc == 2, "Wrong number of arguments"); + + napi_valuetype valuetype0; + NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0)); + + NAPI_ASSERT( + env, valuetype0 == napi_object, + "Wrong type of arguments. Expects a typed array as first argument."); + + napi_value input_array = args[0]; + bool is_typedarray; + NAPI_CALL(env, napi_is_typedarray(env, input_array, &is_typedarray)); + + NAPI_ASSERT( + env, is_typedarray, + "Wrong type of arguments. Expects a typed array as first argument."); + + napi_valuetype valuetype1; + NAPI_CALL(env, napi_typeof(env, args[1], &valuetype1)); + + NAPI_ASSERT(env, valuetype1 == napi_number, + "Wrong type of arguments. Expects a number as second argument."); + + double multiplier; + NAPI_CALL(env, napi_get_value_double(env, args[1], &multiplier)); + + napi_typedarray_type type; + napi_value input_buffer; + size_t byte_offset; + size_t i, length; + NAPI_CALL(env, napi_get_typedarray_info(env, input_array, &type, &length, + NULL, &input_buffer, &byte_offset)); + + void* data; + size_t byte_length; + NAPI_CALL(env, + napi_get_arraybuffer_info(env, input_buffer, &data, &byte_length)); + + napi_value output_buffer; + void* output_ptr = NULL; + NAPI_CALL(env, napi_create_arraybuffer(env, byte_length, &output_ptr, + &output_buffer)); + + napi_value output_array; + NAPI_CALL(env, napi_create_typedarray(env, type, length, output_buffer, + byte_offset, &output_array)); + + if (type == napi_uint8_array) { + uint8_t* input_bytes = (uint8_t*)(data) + byte_offset; + uint8_t* output_bytes = (uint8_t*)(output_ptr); + for (i = 0; i < length; i++) { + output_bytes[i] = (uint8_t)(input_bytes[i] * multiplier); + } + } else if (type == napi_float64_array) { + double* input_doubles = (double*)((uint8_t*)(data) + byte_offset); + double* output_doubles = (double*)(output_ptr); + for (i = 0; i < length; i++) { + output_doubles[i] = input_doubles[i] * multiplier; + } + } else { + napi_throw_error(env, NULL, + "Typed array was of a type not expected by test."); + return NULL; + } + + return output_array; +} + +static napi_value external(napi_env env, napi_callback_info info) { + static int8_t externalData[] = { 0, 1, 2 }; + + napi_value output_buffer; + NAPI_CALL(env, napi_create_external_arraybuffer(env, externalData, + sizeof(externalData), + NULL, // finalize_callback + NULL, // finalize_hint + &output_buffer)); + + napi_value output_array; + NAPI_CALL(env, napi_create_typedarray(env, napi_int8_array, + sizeof(externalData) / sizeof(int8_t), + output_buffer, 0, &output_array)); + + return output_array; +} + +static napi_value create_typed_array(napi_env env, napi_callback_info info) { + size_t argc = 4; + napi_value args[4]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + NAPI_ASSERT(env, argc == 2 || argc == 4, "Wrong number of arguments"); + + napi_value input_array = args[0]; + napi_valuetype valuetype0; + NAPI_CALL(env, napi_typeof(env, input_array, &valuetype0)); + + NAPI_ASSERT( + env, valuetype0 == napi_object, + "Wrong type of arguments. Expects a typed array as first argument."); + + bool is_typedarray; + NAPI_CALL(env, napi_is_typedarray(env, input_array, &is_typedarray)); + + NAPI_ASSERT( + env, is_typedarray, + "Wrong type of arguments. Expects a typed array as first argument."); + + napi_valuetype valuetype1; + napi_value input_buffer = args[1]; + NAPI_CALL(env, napi_typeof(env, input_buffer, &valuetype1)); + + NAPI_ASSERT( + env, valuetype1 == napi_object, + "Wrong type of arguments. Expects an array buffer as second argument."); + + bool is_arraybuffer; + NAPI_CALL(env, napi_is_arraybuffer(env, input_buffer, &is_arraybuffer)); + + NAPI_ASSERT( + env, is_arraybuffer, + "Wrong type of arguments. Expects an array buffer as second argument."); + + napi_typedarray_type type; + napi_value in_array_buffer; + size_t byte_offset; + size_t length; + NAPI_CALL(env, + napi_get_typedarray_info(env, input_array, &type, &length, NULL, + &in_array_buffer, &byte_offset)); + + if (argc == 4) { + napi_valuetype valuetype2; + NAPI_CALL(env, napi_typeof(env, args[2], &valuetype2)); + + NAPI_ASSERT(env, valuetype2 == napi_number, + "Wrong type of arguments. Expects a number as third argument."); + + uint32_t uint32_length; + NAPI_CALL(env, napi_get_value_uint32(env, args[2], &uint32_length)); + length = uint32_length; + + napi_valuetype valuetype3; + NAPI_CALL(env, napi_typeof(env, args[3], &valuetype3)); + + NAPI_ASSERT(env, valuetype3 == napi_number, + "Wrong type of arguments. Expects a number as third argument."); + + uint32_t uint32_byte_offset; + NAPI_CALL(env, napi_get_value_uint32(env, args[3], &uint32_byte_offset)); + byte_offset = uint32_byte_offset; + } + + napi_value output_array; + NAPI_CALL(env, napi_create_typedarray(env, type, length, input_buffer, + byte_offset, &output_array)); + + return output_array; +} + +static napi_value init(napi_env env, napi_value exports) { + napi_property_descriptor descriptors[] = { + DECLARE_NAPI_PROPERTY("Multiply", multiply), + DECLARE_NAPI_PROPERTY("External", external), + DECLARE_NAPI_PROPERTY("CreateTypedArray", create_typed_array), + }; + + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(descriptors) / + sizeof(*descriptors), + descriptors)); + + return exports; +} + +NAPI_MODULE(NODE_GYP_MODULE_NAME, init) diff --git a/test/napi/test_napi_typedarray.js b/test/napi/test_napi_typedarray.js new file mode 100644 index 0000000000..32b7a6c7ec --- /dev/null +++ b/test/napi/test_napi_typedarray.js @@ -0,0 +1,76 @@ +'use strict'; +var assert = require('assert'); +var common = require('common.js'); + +// Testing api calls for arrays +var test_typedarray = require('./build/' + common.buildTypePath + + '/test_napi_typedarray.node'); + +var byteArray = new Uint8Array(3); +byteArray[0] = 0; +byteArray[1] = 1; +byteArray[2] = 2; +assert.strictEqual(byteArray.length, 3); + +var doubleArray = new Float64Array(3); +doubleArray[0] = 0.0; +doubleArray[1] = 1.1; +doubleArray[2] = 2.2; +assert.strictEqual(doubleArray.length, 3); + +var byteResult = test_typedarray.Multiply(byteArray, 3); +assert(byteResult instanceof Uint8Array); +assert.strictEqual(byteResult.length, 3); +assert.strictEqual(byteResult[0], 0); +assert.strictEqual(byteResult[1], 3); +assert.strictEqual(byteResult[2], 6); + +var doubleResult = test_typedarray.Multiply(doubleArray, -3); +assert(doubleResult instanceof Float64Array); +assert.strictEqual(doubleResult.length, 3); +assert.strictEqual(doubleResult[0], -0); +assert.strictEqual(Math.round(10 * doubleResult[1]) / 10, -3.3); +assert.strictEqual(Math.round(10 * doubleResult[2]) / 10, -6.6); + +var externalResult = test_typedarray.External(); +assert(externalResult instanceof Int8Array); +assert.strictEqual(externalResult.length, 3); +assert.strictEqual(externalResult[0], 0); +assert.strictEqual(externalResult[1], 1); +assert.strictEqual(externalResult[2], 2); + +// validate creation of all kinds of TypedArrays +var buffer = new ArrayBuffer(128); +var arrayTypes = [ Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, + Uint16Array, Int32Array, Uint32Array, Float32Array, + Float64Array ]; + +arrayTypes.forEach(function(currentType) { + var template = new currentType(buffer); + var theArray = test_typedarray.CreateTypedArray(template, buffer); + + assert(theArray instanceof currentType, + 'Type of new array should match that of the template. ' + + 'Expected type: ' + currentType.name + + 'actual type: ' + template.constructor.name); + assert.notStrictEqual(theArray, template); + assert.strictEqual(theArray.buffer, buffer); +}); + +arrayTypes.forEach(function(currentType) { + var template = new currentType(buffer); + assert.throws(function() { + test_typedarray.CreateTypedArray(template, buffer, 0, 136); + }, RangeError); +}); + +var nonByteArrayTypes = [ Int16Array, Uint16Array, Int32Array, Uint32Array, + Float32Array, Float64Array ]; +nonByteArrayTypes.forEach(function(currentType) { + var template = new currentType(buffer); + assert.throws(function() { + test_typedarray.CreateTypedArray(template, buffer, + currentType.BYTES_PER_ELEMENT + 1, 1); + console.log('start of offset ' + currentType); + }, RangeError); +}); diff --git a/test/node/common.js b/test/node/common.js index f00d34f16f..c5d7113639 100644 --- a/test/node/common.js +++ b/test/node/common.js @@ -47,7 +47,7 @@ var testRoot = __dirname; // PORT should match the definition in test/testpy/__init__.py. exports.PORT = +process.env.NODE_COMMON_PORT || 12346; -exports.isWindows = process.platform === 'win32'; +exports.isWindows = process.platform === 'windows'; exports.isWOW64 = exports.isWindows && (process.env.PROCESSOR_ARCHITEW6432 !== undefined); exports.isAix = process.platform === 'aix'; @@ -57,6 +57,8 @@ exports.isLinuxPPCBE = (process.platform === 'linux') && exports.isSunOS = process.platform === 'sunos'; exports.isFreeBSD = process.platform === 'freebsd'; exports.isLinux = process.platform === 'linux'; +exports.isNuttX = process.platform === 'nuttx'; +exports.isTizen = process.platform === 'tizen'; exports.isOSX = process.platform === 'darwin'; exports.enoughTestMem = false; @@ -101,7 +103,7 @@ function rmdirSync(p, originalEr) { if (e.code === 'ENOTDIR') throw originalEr; if (e.code === 'ENOTEMPTY' || e.code === 'EEXIST' || e.code === 'EPERM') { - var enc = exports.isLinux ? 'buffer' : 'utf8'; + var enc = (exports.isLinux || exports.isTizen) ? 'buffer' : 'utf8'; fs.readdirSync(p, enc).forEach(function(f) { if (f instanceof Buffer) { var buf = Buffer.concat([Buffer.from(p), Buffer.from(path.sep), f]); @@ -131,7 +133,7 @@ var inFreeBSDJail = null; var localhostIPv4 = null; exports.localIPv6Hosts = ['localhost']; -if (exports.isLinux) { +if (exports.isLinux || exports.isTizen) { exports.localIPv6Hosts = [ // Debian/Ubuntu 'ip6-localhost', @@ -359,7 +361,7 @@ if (global.ArrayBuffer) { knownGlobals.push(Uint32Array); knownGlobals.push(Float32Array); knownGlobals.push(Float64Array); - knownGlobals.push(DataView); + // knownGlobals.push(DataView); } // Harmony features. diff --git a/test/node/parallel/test-http-catch-uncaughtexception.js b/test/node/parallel/test-http-catch-uncaughtexception.js new file mode 100644 index 0000000000..43d857bb33 --- /dev/null +++ b/test/node/parallel/test-http-catch-uncaughtexception.js @@ -0,0 +1,61 @@ +/* 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. + */ + +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; + +var common = require('node/common'); +var assert = require('assert'); +var http = require('http'); + +var uncaughtCallback = common.mustCall(function(er) { + assert.strictEqual(er.message, 'get did fail'); +}); + +process.on('uncaughtException', uncaughtCallback); + +var server = http.createServer(function(req, res) { + res.writeHead(200, { 'Content-Type': 'text/plain' }); + res.end('bye'); + +}).listen(0, function() { + http.get({ port: this.address().port }, function(res) { + res.resume(); + throw new Error('get did fail'); + + }).on('close', function() { + server.close(); + }); +}); diff --git a/test/node/parallel/test-module-circular-b.js b/test/node/parallel/test-module-circular-b.js new file mode 100644 index 0000000000..68937d07e2 --- /dev/null +++ b/test/node/parallel/test-module-circular-b.js @@ -0,0 +1,40 @@ +/* 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. + */ + +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; + +require('./test-module-circular'); + diff --git a/test/node/parallel/test-module-circular.js b/test/node/parallel/test-module-circular.js new file mode 100644 index 0000000000..daf40c2252 --- /dev/null +++ b/test/node/parallel/test-module-circular.js @@ -0,0 +1,43 @@ +/* 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. + */ + +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; +require('node/common'); + +var assert = require('assert'); +require('./test-module-circular-b'); + +assert.ok(true); diff --git a/test/node/parallel/test-net-bind-twice.js b/test/node/parallel/test-net-bind-twice.js index 56336f8bd6..37f9136b2c 100644 --- a/test/node/parallel/test-net-bind-twice.js +++ b/test/node/parallel/test-net-bind-twice.js @@ -46,9 +46,13 @@ server1.listen(0, '127.0.0.1', common.mustCall(function() { var server2 = net.createServer(common.fail); server2.on('error', common.mustCall(function(e) { - // EADDRINUSE have different value on OSX. + // EADDRINUSE has different values on OSX and NuttX. if (common.isOSX) { assert.strictEqual(e, -48); + } else if (common.isNuttX) { + assert.strictEqual(e, -112); + } else if (common.isWindows) { + assert.strictEqual(e, -4091); } else { assert.strictEqual(e, -98); } diff --git a/test/node/parallel/test-net-keepalive.js b/test/node/parallel/test-net-keepalive.js old mode 100755 new mode 100644 diff --git a/test/profiles/host-darwin.profile b/test/profiles/host-darwin.profile new file mode 100644 index 0000000000..397f0d4d4b --- /dev/null +++ b/test/profiles/host-darwin.profile @@ -0,0 +1,3 @@ +ENABLE_MODULE_IOTJS_BASIC_MODULES +ENABLE_MODULE_IOTJS_CORE_MODULES +ENABLE_MODULE_HTTPS diff --git a/test/profiles/host-linux.profile b/test/profiles/host-linux.profile new file mode 100644 index 0000000000..b98be49b6a --- /dev/null +++ b/test/profiles/host-linux.profile @@ -0,0 +1,15 @@ +ENABLE_MODULE_IOTJS_BASIC_MODULES +ENABLE_MODULE_IOTJS_CORE_MODULES +ENABLE_MODULE_ADC +ENABLE_MODULE_BLE +ENABLE_MODULE_CRYPTO +ENABLE_MODULE_DGRAM +ENABLE_MODULE_GPIO +ENABLE_MODULE_HTTP_SIGNATURE +ENABLE_MODULE_HTTPS +ENABLE_MODULE_I2C +ENABLE_MODULE_MQTT +ENABLE_MODULE_PWM +ENABLE_MODULE_SPI +ENABLE_MODULE_UART +ENABLE_MODULE_WEBSOCKET diff --git a/test/profiles/mock-linux.profile b/test/profiles/mock-linux.profile new file mode 100644 index 0000000000..389b8c4db7 --- /dev/null +++ b/test/profiles/mock-linux.profile @@ -0,0 +1,5 @@ +ENABLE_MODULE_IOTJS_BASIC_MODULES +ENABLE_MODULE_IOTJS_CORE_MODULES +ENABLE_MODULE_GPIO +ENABLE_MODULE_I2C +ENABLE_MODULE_PWM diff --git a/test/profiles/nuttx.profile b/test/profiles/nuttx.profile new file mode 100644 index 0000000000..2bca36d7be --- /dev/null +++ b/test/profiles/nuttx.profile @@ -0,0 +1,11 @@ +ENABLE_MODULE_IOTJS_BASIC_MODULES +ENABLE_MODULE_IOTJS_CORE_MODULES +ENABLE_MODULE_ADC +ENABLE_MODULE_CRYPTO +ENABLE_MODULE_DGRAM +ENABLE_MODULE_GPIO +ENABLE_MODULE_I2C +ENABLE_MODULE_PWM +ENABLE_MODULE_SPI +ENABLE_MODULE_STM32F4DIS +ENABLE_MODULE_UART diff --git a/test/profiles/rpi2-linux.profile b/test/profiles/rpi2-linux.profile new file mode 100644 index 0000000000..8aa0719ba4 --- /dev/null +++ b/test/profiles/rpi2-linux.profile @@ -0,0 +1,14 @@ +ENABLE_MODULE_IOTJS_BASIC_MODULES +ENABLE_MODULE_IOTJS_CORE_MODULES +ENABLE_MODULE_BLE +ENABLE_MODULE_CRYPTO +ENABLE_MODULE_DGRAM +ENABLE_MODULE_GPIO +ENABLE_MODULE_HTTP_SIGNATURE +ENABLE_MODULE_HTTPS +ENABLE_MODULE_MQTT +ENABLE_MODULE_I2C +ENABLE_MODULE_PWM +ENABLE_MODULE_SPI +ENABLE_MODULE_UART +ENABLE_MODULE_WEBSOCKET diff --git a/test/profiles/tizen-jerry.profile b/test/profiles/tizen-jerry.profile new file mode 100644 index 0000000000..6e6f71348c --- /dev/null +++ b/test/profiles/tizen-jerry.profile @@ -0,0 +1 @@ +JERRY_ES2015=0 diff --git a/test/profiles/tizen.profile b/test/profiles/tizen.profile new file mode 100644 index 0000000000..507b8bec1c --- /dev/null +++ b/test/profiles/tizen.profile @@ -0,0 +1,15 @@ +ENABLE_MODULE_IOTJS_BASIC_MODULES +ENABLE_MODULE_IOTJS_CORE_MODULES +ENABLE_MODULE_BRIDGE +ENABLE_MODULE_CRYPTO +ENABLE_MODULE_DGRAM +ENABLE_MODULE_GPIO +ENABLE_MODULE_HTTP_SIGNATURE +ENABLE_MODULE_HTTPS +ENABLE_MODULE_MQTT +ENABLE_MODULE_I2C +ENABLE_MODULE_PWM +ENABLE_MODULE_SPI +ENABLE_MODULE_TIZEN +ENABLE_MODULE_UART +ENABLE_MODULE_WEBSOCKET diff --git a/test/profiles/tizenrt.profile b/test/profiles/tizenrt.profile new file mode 100644 index 0000000000..dd7cbd893d --- /dev/null +++ b/test/profiles/tizenrt.profile @@ -0,0 +1,14 @@ +ENABLE_MODULE_IOTJS_BASIC_MODULES +ENABLE_MODULE_IOTJS_CORE_MODULES +ENABLE_MODULE_ADC +ENABLE_MODULE_CRYPTO +ENABLE_MODULE_DGRAM +ENABLE_MODULE_GPIO +ENABLE_MODULE_HTTP_SIGNATURE +ENABLE_MODULE_HTTPS +ENABLE_MODULE_MQTT +ENABLE_MODULE_I2C +ENABLE_MODULE_PWM +ENABLE_MODULE_SPI +ENABLE_MODULE_UART +ENABLE_MODULE_WEBSOCKET diff --git a/test/resources/crypto_public.pem b/test/resources/crypto_public.pem new file mode 100644 index 0000000000..1d549e19b1 --- /dev/null +++ b/test/resources/crypto_public.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsHbJBfgc4tPdH0bkuVoL +AAhN6rxk7RaD73thMVP1KtlyomXdydWT9CEBR/MBepyQaokHHYt430tqbOYeeYss ++SJUp2mU0C+XCcuD27T5lcwbUOFhN8pkerUKvuqM8u+ndYwgEbn8XHXSM+x62qWd +wM6CO/kJx5CtzQaJ+2jPfdPnUYB3BpZvRL4ymzvGa3lUpwmtns3jfyZjJMz7Bd3A +kH9gJTREhTLM3A4LNocgvIFLJNadlTbB5OgMMHxH3EEmXn1Wq+LeC57E4f2PuhmX +vSRLbT85NpGC1U1AmuG2IVitwFkw1Hx23lZG8Zld/ZeV3kLBwJ2o002U3rs+H1aP +8QIDAQAB +-----END PUBLIC KEY----- diff --git a/test/resources/http_signature_key.key b/test/resources/http_signature_key.key new file mode 100644 index 0000000000..88059408d5 --- /dev/null +++ b/test/resources/http_signature_key.key @@ -0,0 +1,8 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv5B5QBJx+XGoK8xbY2Q9L5pJyv0Ddlzx +pwWSz6q049b/+7YzVsFLt7S+O7soW7upfwTxFkCcpWWTKIoRac6vCYY14lTmWK/M1cntho8BiFoL +cvDAx7dXgH2OfIsr6VgJMFl4DZebcN2fvhsZBo2lTyhJt8lSw8esTDHFZ8App6ilvVXJ4p6uKWJp +1bzJQxvwHuNa4itN6GKyMR5kqklDwTa359JXXZf5LO7kFwO7ULCrtliaCUEUvG4xTgZfctD4gKMb +WScMzx2U4ksSFhlmGyxcED2FH+fUn98Qo5KFflu01RaHScodXUZo6VMV5oY466Yq7y7z2R4KdpL4 +vC4v4wIDAQAB +-----END PUBLIC KEY----- diff --git a/test/resources/my_ca.crt b/test/resources/my_ca.crt new file mode 100644 index 0000000000..2f2fb1b2d3 --- /dev/null +++ b/test/resources/my_ca.crt @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIJAMeGQlu8r9jlMA0GCSqGSIb3DQEBCwUAMHQxCzAJBgNV +BAYTAkhVMRMwEQYDVQQIDApTb21lLVN0YXRlMQ8wDQYDVQQHDAZTemVnZWQxDjAM +BgNVBAoMBU15IENBMREwDwYDVQQDDAhteWNhLm9yZzEcMBoGCSqGSIb3DQEJARYN +bXljYUBteWNhLm9yZzAeFw0xODA2MjgxMDQzMThaFw0yODA2MjUxMDQzMThaMHQx +CzAJBgNVBAYTAkhVMRMwEQYDVQQIDApTb21lLVN0YXRlMQ8wDQYDVQQHDAZTemVn +ZWQxDjAMBgNVBAoMBU15IENBMREwDwYDVQQDDAhteWNhLm9yZzEcMBoGCSqGSIb3 +DQEJARYNbXljYUBteWNhLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBALCPKzrZoSVHjswF0W/5pn0ElmAjO3GmYH1rHbTdSfQ9fXWiXWHREcGXeGXJ +Vs/OIr6hxrghuPehYxERW2RhZESosOZgtifLC5hpg5guHzls0p8ix1gZ/olNBhzV +/1qO5J7MSxx87DldDvoVTNyUzp/FEL5U45N4B8ECrY5+41BN1SPgAs5xc+LJLiag +JjrsUxrpzngqsfpf15zcFsXcknB3VZKLQStkbmZB2RNWJm2dulSwr1tdXeZhBs1M +seKh7MZ86ay/8/LJPedBUNUnIm/ZlinFYC5dxRpfA4RFL7Q91PZbAIRMphpXfE2x +SSeOnkB2InXXwaPi+PlQnDzzSIMCAwEAAaNQME4wHQYDVR0OBBYEFNm9NQ9P2i35 +oCIFHQmft53GXlCNMB8GA1UdIwQYMBaAFNm9NQ9P2i35oCIFHQmft53GXlCNMAwG +A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAIurYWyw/AkMlNeW7PIu7zsh +6mknQ0RCI8h05CgJ6SlSlVQSB6Tu9BiLT0DNc0PTIQxHoqgVofATndLLn7a6G0Lc +iy8mcYDbfAEcXiXFlo58gyWCa+/azJ/hslOVKvCs66BieHOiDhaBVzqWwUYaVMYA +EocmusQmx44qrSsMfNPqq4b15b9sn0WximHtc76Czibnj35Nkhr/x2Cd07vnoU/2 +5fpiu8PfrSAjOw6oaAINwP6pXskl1+wtJ9NpqvEJVl4aEUWpSJoGtIJGOtM0zbNF +/IPITiGuLri8FzYqfvYBxRR2Wuq94Vcmwh8r2mysuPC1dHtjg5l1hm8vqiBW3p4= +-----END CERTIFICATE----- diff --git a/test/resources/my_ca.key b/test/resources/my_ca.key new file mode 100644 index 0000000000..7927a53781 --- /dev/null +++ b/test/resources/my_ca.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAsI8rOtmhJUeOzAXRb/mmfQSWYCM7caZgfWsdtN1J9D19daJd +YdERwZd4ZclWz84ivqHGuCG496FjERFbZGFkRKiw5mC2J8sLmGmDmC4fOWzSnyLH +WBn+iU0GHNX/Wo7knsxLHHzsOV0O+hVM3JTOn8UQvlTjk3gHwQKtjn7jUE3VI+AC +znFz4skuJqAmOuxTGunOeCqx+l/XnNwWxdyScHdVkotBK2RuZkHZE1YmbZ26VLCv +W11d5mEGzUyx4qHsxnzprL/z8sk950FQ1Scib9mWKcVgLl3FGl8DhEUvtD3U9lsA +hEymGld8TbFJJ46eQHYiddfBo+L4+VCcPPNIgwIDAQABAoIBAGeShOyP8B07XgRH +QXYrgEQEZeZdpKhlzmKkbJfF3HU/gRJ5vcf86iqjnYgwVRGwPeeQZU9s0OHLNZ80 +jGVVUImKX8O1ZgXv8YxmEUE7hSudr+yUbVY8YXnPyk8uJg7MlkalV0aN7dE0yu1f +g2g+jvtgkhLlH19J4VqTJJbbzqMzG+2m9htQqG2vM2spkYtSw3DbsmJS4zklkr/n +g6VvIzLDzGq6KdIqE0LWvSiPm4pYTXQFk4j+J7UjY+ZmTXZIKedmk3a4vTpppiYu +HAy1I8a5tZtgPYEOnRaZ2sPGuLcOgcBWa9iPx8JelRDcVB/51KcICsYZU/EOzoDc +QHtqswECgYEA1ifEjpF4fTdAnXdrmj5ln3wIBjLd/YNAaOJW6ZWCFJ5Rcper7QYK +2hUG9TvkJ/oq3m4v8X0gdxnOASpHZ5k04JMS58M85ptc4st0wvOvX36qdU9juRz4 +ClnCZDDndc1E7JMkqHl1uJHvDYWLFUYogkk042HIvkTwddNbp1tJL4ECgYEA0w7Q +Dq6YIc+AHUisE0uVtli8kHZu/pQHv2XFZ3zRkwsYOLB5xwJU5uoXRZJcc6yF2EF+ +/kulJDLTwKi2b9UO491Fl071VqlGW086+gPmSDao0RzTGbfhqc3dAtn6fGHp1Vgf +xpsxYTWpoiiexljHfa3NkDIYmgZtElRRR4iUugMCgYEAtol9E5xRHEHdNJsWv4lR +64e3+zieWTjnzL6oID+MefCcMdWv+L8+vrZPkPY0uhKVObSn7umdo4b+PaYA6QAA +vy79XUjf/xwMJ1AOPSGiqP35YzaBJMbZcVEizW2VzKZjila9V1D4E5NoNJlQfJip +bKvjhbDSf8OZRoUaSWMY1YECgYApQqAR/rfnBDW7g9WAACrIdxiF9WFFi5LoK/En +hhNCd8zIaFemPCJ08haSl0ZTpsqTuFonRIqIRRd4doMT4ccDbOKJ7fmwc285soeJ +EPIX8/eUydnLEVOgaopmYE7DujCIcK3lmblRk7gR53cCt6BoRW4GXoTIt7DjAHDT +VzQcGQKBgQDIsplosD3lXeRKA2agTozOROlUbJjYFlPLfztiXVPk3+QvGN1s4NIZ +IzoJX/sufinHYzajRFK+IyAyusmnwHkwZz7WUmgJk0L6K+/T93nQhhwjSue6NMZK +egpitIY58FY1J6Y67MR4+3h0/o4LCYQN5vOcrCAkczsNtAuVO0OnWA== +-----END RSA PRIVATE KEY----- diff --git a/test/resources/my_ca.srl b/test/resources/my_ca.srl new file mode 100644 index 0000000000..28d02ef7b0 --- /dev/null +++ b/test/resources/my_ca.srl @@ -0,0 +1 @@ +94825A52EA8A27F1 diff --git a/test/resources/my_crt.crt b/test/resources/my_crt.crt new file mode 100644 index 0000000000..af3d56c57e --- /dev/null +++ b/test/resources/my_crt.crt @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEazCCA1MCCQCUglpS6oon8TANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJI +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEPMA0GA1UEBwwGU3plZ2VkMQ4wDAYDVQQK +DAVNeSBDQTERMA8GA1UEAwwIbXljYS5vcmcxHDAaBgkqhkiG9w0BCQEWDW15Y2FA +bXljYS5vcmcwHhcNMTgwNjI4MTA0NjA3WhcNMjgwNjI1MTA0NjA3WjB7MQswCQYD +VQQGEwJIVTETMBEGA1UECAwKU29tZS1TdGF0ZTEPMA0GA1UEBwwGU3plZ2VkMRAw +DgYDVQQKDAdUcnVzdGVkMRIwEAYDVQQDDAlsb2NhbGhvc3QxIDAeBgkqhkiG9w0B +CQEWEXRydXN0ZWRAbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC +CgKCAgEApd/5D3T9EWTLcJLTk8ayjc+GdSZBiRNYo4JSACf4LSrTBOif4UN/3PZi +02wmPesPFyPY86cqJGi/7IVxaXX2stKLBRa+ZE7Pp7T9tIjkxx/Rw1GMEHLSjJM4 +JMBUJ2Vb6a0jLPAvNqO9jiXeaw6XJVtvXJrE71zVOj0R1Ttq0b3VQ10oQgZVfaRy +xjMFD2sTMFo7ADkGw+XUqvp0ZMleeOk2yKuflvQkr/BUHzncepBtsMdxGb8Xm58Z +QbVodLlbCD+NAoRpTnVphVxSpGsYRfLNfEHWYA8CD+1J3nPTAYU9t7AxZYPsqcHW +GHc2A6badnwLsg4jNbUGx4bOS2Jwtf5uVQxPLHobI4lMFAZXBBHHuySP3O9WTPB8 +m/SHRFP2TBLARJX4DCpisaeZ2f0kshdUCZaxKCKoiiQ0Eo826iRJItiAOx+Uo3E4 +VP9+qkphOjPW23ERw8EDY5Cm///Pp4q/vlGICTn3peoxDnYcy+FDPvbw+dakQPtK +IxurQC80RqV3f+W6LhVx3uZQYN2FkfOhQaMbfdq+jB6dcrXbh1FUPwa00eaPdfXz +Fq1xWpfzE6GrjThijC0HkGrUT6ThQVG0nrHDhzbKw+27FUDkhwnOrNtCJy1GgS9m +TUD1CvoDfdRSvqP4N1zrxNK4PNnYuN8m/xcycn8i7aMroQFEGSECAwEAATANBgkq +hkiG9w0BAQsFAAOCAQEAd5MuhS49EtJo/dYnLS6MdHQ9Afwc5dlE7375hx1++cDg +rV2XD1RuMovZpwCi58RPTsD+lp9QB/60SkW/85Dvbh7Xmh/u5Cr6J0/drVQpBj7U +++9dVFPs0nHmxkYxC7ZYM+NX1cwbcfLYf9dpjA88tIcVatnFjVoGqaJpZzyd7vRv +UESF9EG1rLAtla36absMwg/rGxH+Rl0If662lCiHHu7jN+lu2uBP8tQ4tWlIxybp +wcEpJqpqN7WnMwFuuriUL3p8zcglsWwIqccKi3M/lYS2uLvHBhF/44W06RM0zwxg +oFr+K2SlC17Xr+A29kL+OmtFdgrVIQAhVZX02v3IkA== +-----END CERTIFICATE----- diff --git a/test/resources/my_csr.csr b/test/resources/my_csr.csr new file mode 100644 index 0000000000..9835e10dab --- /dev/null +++ b/test/resources/my_csr.csr @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIEwDCCAqgCAQAwezELMAkGA1UEBhMCSFUxEzARBgNVBAgMClNvbWUtU3RhdGUx +DzANBgNVBAcMBlN6ZWdlZDEQMA4GA1UECgwHVHJ1c3RlZDESMBAGA1UEAwwJbG9j +YWxob3N0MSAwHgYJKoZIhvcNAQkBFhF0cnVzdGVkQGxvY2FsaG9zdDCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXf+Q90/RFky3CS05PGso3PhnUmQYkT +WKOCUgAn+C0q0wTon+FDf9z2YtNsJj3rDxcj2POnKiRov+yFcWl19rLSiwUWvmRO +z6e0/bSI5Mcf0cNRjBBy0oyTOCTAVCdlW+mtIyzwLzajvY4l3msOlyVbb1yaxO9c +1To9EdU7atG91UNdKEIGVX2kcsYzBQ9rEzBaOwA5BsPl1Kr6dGTJXnjpNsirn5b0 +JK/wVB853HqQbbDHcRm/F5ufGUG1aHS5Wwg/jQKEaU51aYVcUqRrGEXyzXxB1mAP +Ag/tSd5z0wGFPbewMWWD7KnB1hh3NgOm2nZ8C7IOIzW1BseGzkticLX+blUMTyx6 +GyOJTBQGVwQRx7skj9zvVkzwfJv0h0RT9kwSwESV+AwqYrGnmdn9JLIXVAmWsSgi +qIokNBKPNuokSSLYgDsflKNxOFT/fqpKYToz1ttxEcPBA2OQpv//z6eKv75RiAk5 +96XqMQ52HMvhQz728PnWpED7SiMbq0AvNEald3/lui4Vcd7mUGDdhZHzoUGjG33a +vowenXK124dRVD8GtNHmj3X18xatcVqX8xOhq404YowtB5Bq1E+k4UFRtJ6xw4c2 +ysPtuxVA5IcJzqzbQictRoEvZk1A9Qr6A33UUr6j+Ddc68TSuDzZ2LjfJv8XMnJ/ +Iu2jK6EBRBkhAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAgEAd88r+jJGHsPmBfhy +ucNhCIK9VOh+kjlbfSnX0m6VJkNoqxJFx8mZ/fWlwUUW7Ff3WsmeDWEs/s5N6A3+ +NRAwPsuBrFImN/CeCbq0u4SU4+KJObZjmJjWhbXBgzYZQrtG/LvwOUceesDzgSj1 +qKfwSpafEYNeGtRWMcv02ypG7+h9Hbpqr2RpEe0Jgi3LAgW11wJzve/rLpDU3PKP +DsZzx7GvkcWAuqxv3jTH68vJOEmHxUKNSybnvCGHCDcA/f5k0bROOO7RSJ1TQOKr +dYLEMssil69gd/n2GpmXHmYjWx2LRlwuJp7Hm4GOjdmketu6bLotWH+R8lwBFuvH +kDRGaBA2uHmFhtgokKult5zpCiIDw4FHfbC43dg63jGD3k6LrzrxbGbxZUb7tpFZ +z9XJxdFPgzI6eOiiHD3SJikZoeox5AmUDCZOmsrF6Ex2iiTXxbIWfSqaImK8xZp4 +fUx6fDKy24SU+rrGqX8oxABOootPwdT/lsCVB4b/IdtzAugPf1dRDIHYWteohlc8 +4CVebKr0QyaQxH7fBRcTQmVNlJhzYfE6GcXa49G1AzXpEs6Eb3iPPRKRTNTssmZv +ycHkTmWjoWLK1b1wEKK7jY17EXuIbxozIYCVoMXTEeUJtcB8lwt2gBDlASxfQYtB +J8BmS9FN25iWTk5xW52UnpniwDk= +-----END CERTIFICATE REQUEST----- diff --git a/test/resources/my_key.key b/test/resources/my_key.key new file mode 100644 index 0000000000..c7e28e617e --- /dev/null +++ b/test/resources/my_key.key @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIJJwIBAAKCAgEApd/5D3T9EWTLcJLTk8ayjc+GdSZBiRNYo4JSACf4LSrTBOif +4UN/3PZi02wmPesPFyPY86cqJGi/7IVxaXX2stKLBRa+ZE7Pp7T9tIjkxx/Rw1GM +EHLSjJM4JMBUJ2Vb6a0jLPAvNqO9jiXeaw6XJVtvXJrE71zVOj0R1Ttq0b3VQ10o +QgZVfaRyxjMFD2sTMFo7ADkGw+XUqvp0ZMleeOk2yKuflvQkr/BUHzncepBtsMdx +Gb8Xm58ZQbVodLlbCD+NAoRpTnVphVxSpGsYRfLNfEHWYA8CD+1J3nPTAYU9t7Ax +ZYPsqcHWGHc2A6badnwLsg4jNbUGx4bOS2Jwtf5uVQxPLHobI4lMFAZXBBHHuySP +3O9WTPB8m/SHRFP2TBLARJX4DCpisaeZ2f0kshdUCZaxKCKoiiQ0Eo826iRJItiA +Ox+Uo3E4VP9+qkphOjPW23ERw8EDY5Cm///Pp4q/vlGICTn3peoxDnYcy+FDPvbw ++dakQPtKIxurQC80RqV3f+W6LhVx3uZQYN2FkfOhQaMbfdq+jB6dcrXbh1FUPwa0 +0eaPdfXzFq1xWpfzE6GrjThijC0HkGrUT6ThQVG0nrHDhzbKw+27FUDkhwnOrNtC +Jy1GgS9mTUD1CvoDfdRSvqP4N1zrxNK4PNnYuN8m/xcycn8i7aMroQFEGSECAwEA +AQKCAgBU1Z3dx+l+MdzScGWBWMgNOyv7UluGLbzRs18Y8Vg+UX6nLgpG/Wyxp9mX +Y+KTHFsVbKISy1YEVQaDgyQj2c8YWhH7wkwRpTUTAsAWy0SmiqGPkW9fIjqI5up5 +8VuY4oAFnSU2YIjlGw1hXADLJCUtV/w2knlSKlprdLxgIAlbyAkAcO6cBf1HSwng +UEuwPQUNX7h5PrE1E6CW6Y0J1utYT35TV2NBow/4Y6PCbKdUj/VpyjcQAemjD9Wt +A4iu2fWy3D3UIcBx/h6/tB4YNSWu8KUjfdCURFi7qJJ1ESvDxU9xWM2Kq9QoZhiH +XsDjUTy+CGc643wihbk35rwvVeNqfN2GfkrrdyTzqIszJAqKtImoXv8BuEf+kgeX +0s9Wtl8BF4Hv6jAZ28NI1DwXXjEFkuqG6Z1yn5UTAxcmKqAudZFVoI5dgeGu8c6x +LVkudR7QOkeSuHTrn4ILYiWMsuP8No/qmnQBCHbfJT4xp2dBHdZ0vDml7LFZjzg1 +If1ZGStOBB7uZqDXyx4wdYdMdV05dvUelWwJqI0KLWF8doX6fr+Huh1Q3owYoOQ5 +MZOoXbHMegu5fOrkDFfaYeATTnCeE1RjoYjT9zf4rYjX3IOryj66b0DadXpYdNhk +5vSAA+NRj3fLGFScdCFxwJjwPbw1Xsn0uSwRHHEQnF9H5hmsoQKCAQEA5poLkJ1s +1ZeEWVr5CDU0js8QsEbeRGpXsm+Aj9X9gf4+D3HQ573lnXO8wiB+PoikETWp45Jf +yq1XK2dcbygcxrSo6Zr+GtzE6grCztn8jE4omkqduJhViAr4hdg59R4UdNG1Qpgg +Z9cFBYwnI/IWMJJBTiqKIVwD3RKQM75WKDT/ccDtUp2MxxNjUKAsVHpmOHW2ZC4T +A2vwbqp+egQ5SfSUBcGkD034PjG2uOJGmHXcKnnG4Dm+9SeutvTF9JZwMJmg3WlG +5AdVUnl4qN2g4t3TYasV4Y8i00EJPcQW5v4UV9sq4dAQ0GXfu/r/TXwMKkQp/cN1 +95I+xXsBjKQDdQKCAQEAuCTqVZJMZ5uovPzyPmnMOBqdtac5Hd7/eglN945sAK7n +ssg3X1hRsHCf8Dx1X95lxCDVn97ac9C2uIEeiLy/+JDFQcOxcgj1vDeF6IaGzaFh +Dc9qIDo4b0bhhD1kMxtowOAkI4YR/+iSIuGOJXq7wu71a6+dIm4meb+4d3L+O5Jq +sOsOBLClL7Ymv1iZ3fol0XPQsuSv1eGoDqDdiNNXOBJHgKy0zMEXs4hpjL2vCGDN +m8MbtqpMg4jCuesy/zh/b+CCkrX0AdW/fkw/euZ/ZTMEageqH5RfitX9CGOw2CuS ++78XmWeFqbr2YVbAZFo09I8Ytv40yO1ZyVQkyKSlfQKCAQA1ooCsGyF0MHCVA+bG +NPHLgXfFOEZ8LSvGkc6aJdB3yrWOjA9lxzI/w+qUUFBspQVcB1pDVwk2r8iFjN3f +8Ll4sg5Tfzw47T5TnTsgN21ZCNjCwjYa+Dt0j/Cr2NXqIBvr69a37YAkBsvhNW7p +GmZ015+e2aAVEDzJz4aAsnWBlooPYCsSuxhCOU0xNH/7Chj6as6IUHsVoaZjZv5R +zOeyPtOq3xYUhTMG7DMun1qCHW+e5YIPJv82MAuf/CCKue7QLvtOZC0b3mTG8P/S +bvH7slJ29f753nvgHNFUb2ZQRapfoNdBfE5c2kUGiOOWlxKRRhdqMWsfsQEul2SN +3Jv9AoIBAASuW46lU2/m0xlKzNWtVtWuR4gQojESNChkCClc43349EblNBMmaZ00 +n7w5rTosqyWbOBMCVUdQbPSvw5jyQ2cMNxd+5AnkFGsedjb9BHxBt/fj5+y9ziV2 +BdGYxe1OqxEMIZ8Nj3OT8/MTDMwDHLbN4EtGgZYYer3pk8TllXTqOfAZaZfQ7cIS +vVVr6S1taHy0lv+VNKsZO25zxG3wAW2ZeVvaCBaUagfUVeqP/90UqOVmxlOUbLGD +Tn/vbLJ0Ozka2fbkzTkmt+F8CrkTFvX5oAkZ/MckvHEJE4+dCSfVo7zmlLD/orQ3 +3n+G9wkWCfaVlKlCORFKh1fI3c6D8PkCggEAI/zEfC6+CndqrmehoCGgHZMP7B+a +rytCeG3Qyoqjta0sKGC8/LUe85PSWDR9xHrrWgEriRF9gHvYxF8YCBXhfInIHDd+ +pdcsWEaoUWlvBqhbKaPhVF/0difpjogWH388sdVXT6PefHEO5maYii9EaPjWckKf +314Eh0KW/oUiSo5rwAgdnu1J84qBOxXqMI2eDZaKLphueytHjt7QRnZW91zeYwrP +3E7MbkKVJPaViIm3MvXUUsL8Gpqji9MY0wHjZAq1PXtZ5WP+K3wHUOte6OGkBcSQ +7oUxhOoMlN0VC4FGtSHu1LLTvmWeYrHk9J6mpfNAj1/TfA/VvVKpNQVlaw== +-----END RSA PRIVATE KEY----- diff --git a/test/resources/promise_chain_calls/1.txt b/test/resources/promise_chain_calls/1.txt new file mode 100644 index 0000000000..c2db73f0b1 --- /dev/null +++ b/test/resources/promise_chain_calls/1.txt @@ -0,0 +1 @@ +Content of 1.txt diff --git a/test/resources/promise_chain_calls/2.txt b/test/resources/promise_chain_calls/2.txt new file mode 100644 index 0000000000..397ecd37cb --- /dev/null +++ b/test/resources/promise_chain_calls/2.txt @@ -0,0 +1 @@ +Content of 2.txt diff --git a/test/resources/promise_chain_calls/3.txt b/test/resources/promise_chain_calls/3.txt new file mode 100644 index 0000000000..af50a79e43 --- /dev/null +++ b/test/resources/promise_chain_calls/3.txt @@ -0,0 +1 @@ +Content of 3.txt diff --git a/test/resources/promise_chain_calls/4.txt b/test/resources/promise_chain_calls/4.txt new file mode 100644 index 0000000000..7a7284d543 --- /dev/null +++ b/test/resources/promise_chain_calls/4.txt @@ -0,0 +1 @@ +Content of 4.txt diff --git a/test/resources/test.json b/test/resources/test.json new file mode 100644 index 0000000000..0e22441f61 --- /dev/null +++ b/test/resources/test.json @@ -0,0 +1,8 @@ +{ + "name": "IoT.js", + "description": "Platform for Internet of Things with JavaScript", + "author": "Samsung Electronics Co., Ltd.", + "license": "Apache-2.0", + "number": 123, + "array": [1,2,3,4] +} diff --git a/test/run_fail/test-issue-1349.js b/test/run_fail/test-issue-1349.js new file mode 100644 index 0000000000..790b1a736b --- /dev/null +++ b/test/run_fail/test-issue-1349.js @@ -0,0 +1,18 @@ +/* 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 dns = require( 'dns' ); +var assert = require( 'assert' ); +assert.throws(function ( ) { dns.lookup ('localhost', require) } ); diff --git a/test/run_fail/test-issue-1360.js b/test/run_fail/test-issue-1360.js new file mode 100644 index 0000000000..0eea6c1147 --- /dev/null +++ b/test/run_fail/test-issue-1360.js @@ -0,0 +1,17 @@ +/* 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. + */ + +process.on('exit', function() {}); +setTimeout(function() { Array.prototype.slice += 'B' }, 500); diff --git a/src/js/testdriver.js b/test/run_fail/test-issue-1570.js similarity index 82% rename from src/js/testdriver.js rename to test/run_fail/test-issue-1570.js index 1dc0d740f4..b94ca26ea2 100644 --- a/src/js/testdriver.js +++ b/test/run_fail/test-issue-1570.js @@ -1,4 +1,4 @@ -/* Copyright 2016-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. @@ -13,4 +13,5 @@ * limitations under the License. */ -module.exports = process.binding(process.binding.testdriver); +Object.freeze(process); +throw new Error("Some error"); diff --git a/test/run_fail/test-issue-1915.js b/test/run_fail/test-issue-1915.js new file mode 100644 index 0000000000..80bdb2b453 --- /dev/null +++ b/test/run_fail/test-issue-1915.js @@ -0,0 +1,17 @@ +/* Copyright 2019-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 uart = require('uart'); +uart.open(this); diff --git a/test/run_fail/test-issue-1917.js b/test/run_fail/test-issue-1917.js new file mode 100644 index 0000000000..2040a55e6d --- /dev/null +++ b/test/run_fail/test-issue-1917.js @@ -0,0 +1,17 @@ +/* Copyright 2019-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 fs = require('fs') +setInterval(fs.fstatSync(1).isFile, 1); diff --git a/test/run_fail/test_module_require_path_below_root.js b/test/run_fail/test_module_require_path_below_root.js new file mode 100644 index 0000000000..2f1b66b7a1 --- /dev/null +++ b/test/run_fail/test_module_require_path_below_root.js @@ -0,0 +1,28 @@ +/* Copyright 2015-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. + */ + + +require('../../../../../../../../../../../../../../../../../../../../../../' + + '../../../../../../../../../../../../../../../../../../../../../../../../' + + '../../../../../../../../../../../../../../../../../../../../../../../../' + + '../../../../../../../../../../../../../../../../../../../../../../../../' + + '../../../../../../../../../../../../../../../../../../../../../../../../' + + '../../../../../../../../../../../../../../../../../../../../../../../../' + + '../../../../../../../../../../../../../../../../../../../../../../../../' + + '../../../../../../../../../../../../../../../../../../../../../../../../' + + '../../../../../../../../../../../../../../../../../../../../../../../../' + + '../../../../../../../../../../../../../../../../../../../../../../../../' + + '../../../../../../../../../../../../../../../../../../../../../../../../' + + '../../../../../../../../../../../../file path below root'); diff --git a/test/run_fail/test_timers_issue_1353.js b/test/run_fail/test_timers_issue_1353.js new file mode 100644 index 0000000000..6dd11d554d --- /dev/null +++ b/test/run_fail/test_timers_issue_1353.js @@ -0,0 +1,16 @@ +/* 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. + */ + +setTimeout(function() { throw "error" }, 100); diff --git a/test/run_pass/issue/issue-1046.js b/test/run_pass/issue/issue-1046.js new file mode 100644 index 0000000000..1ae5a96072 --- /dev/null +++ b/test/run_pass/issue/issue-1046.js @@ -0,0 +1,19 @@ +/* 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 Buffer = require('buffer'); +var assert = require('assert'); + +assert.equal(Buffer("").readUInt16LE(10, true), 0); diff --git a/test/run_pass/issue/issue-1077.js b/test/run_pass/issue/issue-1077.js new file mode 100644 index 0000000000..2836df2e20 --- /dev/null +++ b/test/run_pass/issue/issue-1077.js @@ -0,0 +1,23 @@ +/* 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'); + +try { + var m = require('issue-1077'); +} catch (e) { + assert(e.name === 'Error'); + assert(e.message == 'Module not found: issue-1077'); +} diff --git a/samples/gpio_led.js b/test/run_pass/issue/issue-1101.js similarity index 57% rename from samples/gpio_led.js rename to test/run_pass/issue/issue-1101.js index c0decace86..5f88577637 100644 --- a/samples/gpio_led.js +++ b/test/run_pass/issue/issue-1101.js @@ -13,27 +13,31 @@ * limitations under the License. */ -var Gpio = require('gpio'); -var pin = require('systemio_pin').pin; - -var gpio = new Gpio(); - -var gpio_led = gpio.open({ - pin: pin.led1, - direction: gpio.DIRECTION.OUT +var uart = require('uart'); +var res = uart.open({ + device: '/dev/ttyS1', + baudRate: 115200, + dataBits: 8 }, function(err) { - if (!err) { - gpio_led.writeSync(true); - - var interval = setInterval(function() { - gpio_led.read(function(err, value) { - if (!err) { - console.log("read value:%d", value); - gpio_led.write(!value); - } else { - clearInterval(interval); - } - }); - }, 1000); + if (err) { + console.error(err); + } else { + console.log('opened'); + res.close(function(err) { + if (err) { + console.error(err); + } else { + console.log('closed'); + } + }); + var c = 0; + var p = function() { + c++; + console.log('this should still run'); + if (c < 10) { + setTimeout(p, 250); + } + }; + p(); } }); diff --git a/test/run_pass/issue/issue-1165.js b/test/run_pass/issue/issue-1165.js new file mode 100644 index 0000000000..6b78e7ba17 --- /dev/null +++ b/test/run_pass/issue/issue-1165.js @@ -0,0 +1,18 @@ +/* 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 s1 = Buffer('737263', 'hex').toString(); +var s2 = new Buffer('737263', 'hex').toString() +assert(s1 === s2); diff --git a/test/run_pass/issue/issue-1348.js b/test/run_pass/issue/issue-1348.js new file mode 100644 index 0000000000..e490963221 --- /dev/null +++ b/test/run_pass/issue/issue-1348.js @@ -0,0 +1,17 @@ +/* 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. + */ + + process.on('uncaughtException', function(err) { } ); + process.exit('callback'); diff --git a/src/js/constants.js b/test/run_pass/issue/issue-1350.js similarity index 91% rename from src/js/constants.js rename to test/run_pass/issue/issue-1350.js index a2f9e4d14f..0c3645dd4a 100644 --- a/src/js/constants.js +++ b/test/run_pass/issue/issue-1350.js @@ -13,5 +13,4 @@ * limitations under the License. */ - -module.exports = process.binding(process.binding.constants); +process.on('exit', function() { process.exit("callback"); } ); diff --git a/test/run_pass/issue/issue-1463.js b/test/run_pass/issue/issue-1463.js new file mode 100644 index 0000000000..e64471d730 --- /dev/null +++ b/test/run_pass/issue/issue-1463.js @@ -0,0 +1,31 @@ +/* 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 assert = require('assert'); + +function readfile(fileName) { + return new Promise(function(resolve, reject) { + throw function() {}(), Buffer; + }); +}; + +try { + readfile(readfile).then(function(value) { + loadfi([], 0); + }).prototype(function(e) {}); + assert(false); +} catch (ex) { + assert(ex instanceof TypeError); +} diff --git a/test/run_pass/issue/issue-1485.js b/test/run_pass/issue/issue-1485.js new file mode 100644 index 0000000000..83ebbb8e25 --- /dev/null +++ b/test/run_pass/issue/issue-1485.js @@ -0,0 +1,16 @@ +/* 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. + */ + +process.emitExit = 1; diff --git a/test/run_pass/issue/issue-1507.js b/test/run_pass/issue/issue-1507.js new file mode 100644 index 0000000000..21309241cb --- /dev/null +++ b/test/run_pass/issue/issue-1507.js @@ -0,0 +1,17 @@ +/* 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 x = require("console"); +process.exitCode = x.id_0; diff --git a/test/run_pass/issue/issue-1557.js b/test/run_pass/issue/issue-1557.js new file mode 100644 index 0000000000..3c51283221 --- /dev/null +++ b/test/run_pass/issue/issue-1557.js @@ -0,0 +1,22 @@ +/* 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 fz_globalObject = Function("return this")( ) +var prop_names = Object.getOwnPropertyNames(fz_globalObject) +console.log(prop_names) +for (var i = 0; i < 10; i++) { + var prop_name = prop_names[i] + console.log(prop_name) +} diff --git a/test/run_pass/issue/issue-1897.js b/test/run_pass/issue/issue-1897.js new file mode 100644 index 0000000000..b0f490a4ff --- /dev/null +++ b/test/run_pass/issue/issue-1897.js @@ -0,0 +1,28 @@ +/* Copyright 2019-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 websocket = require('websocket'); +var client = new websocket.Websocket(); +var client2 = new websocket.Websocket(); +var wss = new websocket.Server({port: 8081}, function () {}); + +client.connect('ws://localhost', 8081, '/', function() { + client2.connect('ws://localhost', 8081, '/'); + client2.on('open', function() { + wss.broadcast('a'); + // prevent blocking + wss.close(); + }); +}); diff --git a/tools/common_js/module/console.js b/test/run_pass/issue/issue-1904.js similarity index 65% rename from tools/common_js/module/console.js rename to test/run_pass/issue/issue-1904.js index 4aac72a0e2..b10fd1ce34 100644 --- a/tools/common_js/module/console.js +++ b/test/run_pass/issue/issue-1904.js @@ -1,4 +1,4 @@ -/* Copyright 2016-present Samsung Electronics Co., Ltd. and other contributors +/* Copyright 2019-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. @@ -13,17 +13,13 @@ * limitations under the License. */ -var fs = require('fs'); +var module = require('module'); +var dgram = require('dgram'); +var assert = require('assert'); -function Console() { - return this; +try { + dgram.createSocket('udp4')._handle.send(this, 0, '', new module()); + assert(false); +} catch (e) { + assert(e instanceof TypeError); } - -Console.prototype.log = -Console.prototype.info = -Console.prototype.warn = -Console.prototype.error = function() { - /* Do Nothing */ -}; - -module.exports = new Console(); diff --git a/test/run_pass/require1/test_index2/add2.js b/test/run_pass/require1/test_index2/add2.js new file mode 100644 index 0000000000..2e2ec6a6d9 --- /dev/null +++ b/test/run_pass/require1/test_index2/add2.js @@ -0,0 +1,18 @@ +/* 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. + */ + +exports.add2 = function(a, b) { + return a + b; +} diff --git a/test/run_pass/require1/test_index2/index_test.js b/test/run_pass/require1/test_index2/index_test.js new file mode 100644 index 0000000000..5f78dab757 --- /dev/null +++ b/test/run_pass/require1/test_index2/index_test.js @@ -0,0 +1,22 @@ +/* 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. + */ + + exports.add = function(a, b) { + return a + b; +}; + +var x = require("lib/multi.js"); +exports.multi = x.multi; +exports.add2 = x.add2; diff --git a/test/run_pass/require1/test_index2/lib/multi.js b/test/run_pass/require1/test_index2/lib/multi.js new file mode 100644 index 0000000000..ca10e5aa59 --- /dev/null +++ b/test/run_pass/require1/test_index2/lib/multi.js @@ -0,0 +1,20 @@ +/* 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. + */ + +exports.multi = function(a, b) { + return a * b; +}; + +exports.add2 = require('../add2').add2; diff --git a/test/run_pass/require1/test_index2/package.json b/test/run_pass/require1/test_index2/package.json new file mode 100644 index 0000000000..25840360a5 --- /dev/null +++ b/test/run_pass/require1/test_index2/package.json @@ -0,0 +1,3 @@ +{ + "main": "index_test" +} diff --git a/test/run_pass/test_adc.js b/test/run_pass/test_adc.js index 63024672f1..f67b9e208e 100644 --- a/test/run_pass/test_adc.js +++ b/test/run_pass/test_adc.js @@ -14,9 +14,8 @@ */ -var Adc = require('adc'); +var adc = require('adc'); var assert = require('assert'); -var adc = new Adc(); var configuration = {}; if (process.platform === 'linux') { @@ -24,19 +23,21 @@ if (process.platform === 'linux') { '/sys/devices/12d10000.adc/iio:device0/in_voltage0_raw'; } else if (process.platform === 'nuttx') { configuration.pin = require('stm32f4dis').pin.ADC1_3; +} else if (process.platform === 'tizenrt') { + configuration.pin = 0; } else { - assert.fail(); + assert.assert(false, "Unsupported platform: " + process.platform); } +// start async test asyncTest(); -// read async test function asyncTest() { var adc0 = adc.open(configuration, function(err) { console.log('ADC initialized'); if (err) { - assert.fail(); + assert.assert(false, "Failed to open device."); } var loopCnt = 5; @@ -46,13 +47,16 @@ function asyncTest() { if (--loopCnt < 0) { console.log('test1 complete'); clearInterval(test1Loop); - adc0.closeSync(); - syncTestst(); + adc0.close(function (err) { + assert.equal(err, null); + + // start sync test + syncTest(); + }); } else { adc0.read(function(err, value) { if (err) { - console.log('read failed'); - assert.fail(); + assert.assert(false, "Failed to read device."); } console.log(value); @@ -62,33 +66,31 @@ function asyncTest() { }); } -// read sync test -function syncTestst() { - var adc0 = adc.open(configuration, function(err) { - console.log('ADC initialized'); - - if (err) { - assert.fail(); - } +function syncTest() { + var adc0 = adc.openSync(configuration); + console.log('ADC initialized'); - var loopCnt = 5, - value = -1; + var loopCnt = 5, + value = -1; - console.log('test2 start(read sync test)'); - var test2Loop = setInterval(function() { - if (--loopCnt < 0) { - console.log('test2 complete'); - clearInterval(test2Loop); - adc0.close(); + console.log('test2 start(read sync test)'); + var test2Loop = setInterval(function() { + if (--loopCnt < 0) { + console.log('test2 complete'); + clearInterval(test2Loop); + adc0.closeSync(); + } else { + value = adc0.readSync(); + if (value < 0) { + assert.assert(false, "Failed to read device."); } else { - value = adc0.readSync(); - if (value < 0) { - console.log('read failed'); - assert.fail(); - } else { - console.log(value); - } + console.log(value); } - }, 1000); - }); + } + }, 1000); } + +// error test +assert.throws(function() { + var adc = adc.open(configuration); +}, TypeError, 'Calling adc.open without a callback function.'); diff --git a/test/run_pass/test_buffer.js b/test/run_pass/test_buffer.js index 3d0664d88f..5f1d251b22 100644 --- a/test/run_pass/test_buffer.js +++ b/test/run_pass/test_buffer.js @@ -19,15 +19,15 @@ var assert = require('assert'); var buff1 = new Buffer("test"); assert.equal(buff1.toString(), "test"); -assert.equal(buff1.toString(0, 0), ""); -assert.equal(buff1.toString(0, 1), "t"); -assert.equal(buff1.toString(0, 2), "te"); -assert.equal(buff1.toString(0, 3), "tes"); -assert.equal(buff1.toString(0, 4), "test"); -assert.equal(buff1.toString(1, 4), "est"); -assert.equal(buff1.toString(2, 4), "st"); -assert.equal(buff1.toString(3, 4), "t"); -assert.equal(buff1.toString(4, 4), ""); +assert.equal(buff1.toString(undefined, 0, 0), ""); +assert.equal(buff1.toString(undefined, 0, 1), "t"); +assert.equal(buff1.toString(undefined, 0, 2), "te"); +assert.equal(buff1.toString(undefined, 0, 3), "tes"); +assert.equal(buff1.toString(undefined, 0, 4), "test"); +assert.equal(buff1.toString(undefined, 1, 4), "est"); +assert.equal(buff1.toString(undefined, 2, 4), "st"); +assert.equal(buff1.toString(undefined, 3, 4), "t"); +assert.equal(buff1.toString(undefined, 4, 4), ""); assert.equal(buff1.length, 4); var buff2 = new Buffer(10); diff --git a/test/run_pass/test_buffer_builtin.js b/test/run_pass/test_buffer_builtin.js deleted file mode 100644 index 66d3d572e8..0000000000 --- a/test/run_pass/test_buffer_builtin.js +++ /dev/null @@ -1,111 +0,0 @@ -/* Copyright 2016-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 buff1 = new Buffer("test"); -assert.equal(buff1._builtin.toString(0, 0), ""); -assert.equal(buff1._builtin.toString(0, 1), "t"); -assert.equal(buff1._builtin.toString(0, 2), "te"); -assert.equal(buff1._builtin.toString(0, 3), "tes"); -assert.equal(buff1._builtin.toString(0, 4), "test"); -assert.equal(buff1._builtin.toString(1, 4), "est"); -assert.equal(buff1._builtin.toString(2, 4), "st"); -assert.equal(buff1._builtin.toString(3, 4), "t"); -assert.equal(buff1._builtin.toString(4, 4), ""); - -assert.equal(buff1._builtin.toString(-1, 5), "test"); -assert.equal(buff1._builtin.toString(-1, 2), "te"); -assert.equal(buff1._builtin.toString(2, 5), "st"); - - -var buff2 = new Buffer(10); -buff2._builtin.write("abcde", 0, 5); -assert.equal(buff2.toString(), "abcde"); -assert.equal(buff2.length, 10); - -buff2._builtin.write("fgh", 5, 3); -assert.equal(buff2.toString(), "abcdefgh"); -assert.equal(buff2.length, 10); - -buff2._builtin.write("AB", 0, 10); -assert.equal(buff2.toString(), "ABcdefgh"); -assert.equal(buff2.length, 10); - -buff2._builtin.write("ab", -1, 11); -assert.equal(buff2.toString(), "abcdefgh"); -assert.equal(buff2.length, 10); - -buff2._builtin.write("ijklmnopqrstu", 8, 5); -assert.equal(buff2.toString(), "abcdefghij"); -assert.equal(buff2.length, 10); - -buff2._builtin.write("\0\0", 8, 2); -assert.equal(buff2.toString(), "abcdefgh"); -assert.equal(buff2.length, 10); - - -var buff3 = Buffer.concat([buff1, buff2]); - - -var buff4 = new Buffer(10); -var buff5 = new Buffer('a1b2c3'); -buff5._builtin.copy(buff4, 0, 0, 6); -assert.equal(buff4.toString(), 'a1b2c3'); -buff5._builtin.copy(buff4, 4, 2, 6); -assert.equal(buff4.toString(), 'a1b2b2c3'); - - -var buff6 = buff3._builtin.slice(1, buff3.length); -assert.equal(buff6.toString(), 'estabcdefgh'); -assert.equal(buff6.length, 13); - -var buff7 = buff6._builtin.slice(3, 5); -assert.equal(buff7.toString(), 'ab'); -assert.equal(buff7.length, 2); - -var buff8 = new Buffer(buff5); -assert.equal(buff8.toString(), 'a1b2c3'); -assert.equal(buff8.equals(buff5), true); -assert.equal(buff8.equals(buff6), false); - -var buff9 = new Buffer('abcabcabcd'); -var buff10 = buff9._builtin.slice(0, 3); -var buff11 = buff9._builtin.slice(3, 6); -var buff12 = buff9._builtin.slice(6, buff9.length); -assert.equal(buff10.equals(buff11), true); -assert.equal(buff11.equals(buff10), true); -assert.equal(buff11.equals(buff12), false); -assert.equal(buff10.compare(buff11), 0); -assert.equal(buff11.compare(buff10), 0); -assert.equal(buff11.compare(buff12), -1); -assert.equal(buff12.compare(buff11), 1); - -assert.equal(buff9._builtin.slice(-2, buff9.length).toString(), 'cd'); -assert.equal(buff9._builtin.slice(-3, -2).toString(), 'b'); -assert.equal(buff9._builtin.slice(0, -2).toString(), 'abcabcab'); - - -assert.equal(buff3.toString(), 'testabcdefgh'); - - -assert.equal(Buffer.byteLength('\u007F'), 1); -assert.equal(Buffer.byteLength('\u008F'), 2); -assert.equal(Buffer.byteLength('\u08FF'), 3); -assert.equal(Buffer.byteLength('abc'), 'abc'.length); -assert.notEqual(Buffer.byteLength('\u2040'), '\u2040'.length); diff --git a/test/run_pass/test_buffer_from.js b/test/run_pass/test_buffer_from.js new file mode 100644 index 0000000000..18a2008c74 --- /dev/null +++ b/test/run_pass/test_buffer_from.js @@ -0,0 +1,46 @@ +/* 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 assert = require('assert'); + +var array_src = [65, 66, 67]; +var buff = Buffer.from(array_src, 0, 3); +assert.equal(buff.toString(), "ABC"); +var buff2 = Buffer.from(array_src, 0, -3); +// Buffer.from(string, encoding) +var string_utf = "ABC"; +var buff3 = Buffer.from(string_utf, 'utf8'); +assert.equal(buff3.toString(), "ABC"); + +var string_hex = "414243"; +var buff4 = Buffer.from(string_hex, 'hex'); +assert.equal(buff4.toString(), "ABC"); + +// Buffer.from(Buffer) +var buffer_src = new Buffer([0x41, 0x42, 0x43]); +var buff5 = Buffer.from(buffer_src); +assert.equal(buff5.toString(), "ABC"); + +var buff_undef = new Buffer(10); +var buff6 = Buffer.from(buff_undef); +assert.equal(buff6.toString(), buff_undef.toString()); + +// Corner case tests +var obj = {}; +var num = 5; +assert.throws(function() { var buffer = Buffer.from(obj); }, + TypeError); +assert.throws(function() { var buffer = Buffer.from(num); }, + TypeError); diff --git a/test/run_pass/test_buffer_from_arraybuffer.js b/test/run_pass/test_buffer_from_arraybuffer.js new file mode 100644 index 0000000000..f6918f2227 --- /dev/null +++ b/test/run_pass/test_buffer_from_arraybuffer.js @@ -0,0 +1,81 @@ +/* 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 assert = require('assert'); + +var source = new ArrayBuffer(10); + +//creation tests +var buff1 = Buffer.from(source, 0, 10); +assert.equal(buff1.length, 10); +var buff2 = Buffer.from(source, 3, 7); +assert.throws(function() { var buffer = buffer.from(source, 3, 10) }) +assert.equal(buff2.length, 7); +var buff3 = Buffer.from(source, 10, 0); +assert.equal(buff3.length, 0); +var buff4 = Buffer.from(source, 0, 0); +assert.equal(buff4.length, 0); +assert.throws(function() { var buffer = Buffer.from(source, 0, 1000); }, + RangeError); +assert.throws(function() { var buffer = Buffer.from(source, 1000, 9); }, + RangeError); +assert.throws(function() { var buffer = Buffer.from(source, 1000, 1000); }, + RangeError); + +var buff5 = Buffer.from(source, undefined, 10); +assert.equal(buff5.length, 10); +var buff6 = Buffer.from(source, undefined, 0); +assert.equal(buff6.length, 0); + +var buff7 = Buffer.from(source, undefined, -10); +assert.equal(buff7.length, 0); +var buff8 = Buffer.from(source, 0, undefined); +assert.equal(buff8.length, 10); +var buff9 = Buffer.from(source, 10, undefined); +assert.equal(buff9.length, 0); +assert.throws(function() {var buffer = Buffer.from(source, -10, undefined); }, + RangeError); +var buff10 = Buffer.from(source, undefined, undefined); +assert.equal(buff10.length, 10); + +var buff11 = Buffer.from(source, NaN, 10); +assert.equal(buff11.length, 10); +var buff12 = Buffer.from(source, NaN, 0); +assert.equal(buff12.length, 0); +var buff13 = Buffer.from(source, NaN, -10); +assert.equal(buff13.length, 0); + +var buff14 = Buffer.from(source, 0, NaN); +assert.equal(buff14.length, 0); + +var buff15 = Buffer.from(source, 10, NaN); +assert.equal(buff15.length, 0); +assert.throws(function() { var buffer = Buffer.from(source, -10, NaN); }, + RangeError); + +//value checks +var typed_source1 = new Uint8Array([65, 66]); +var arr_buff = Buffer.from(typed_source1.buffer, 0, 2); +assert.equal(arr_buff.toString('utf-8'), 'AB'); + +var typed_source2 = new Uint16Array([65, 66]); +var arr_buff2 = Buffer.from(typed_source2.buffer, 0, 1); +var arr_buff3 = Buffer.from(typed_source2.buffer, 2, 1); +assert.equal(arr_buff2.toString(), 'A'); +assert.equal(arr_buff3.toString(), 'B'); + +var typed_source3 = new Uint8Array([42, 43]); +var arr_buff4 = Buffer.from(typed_source3.buffer, 0, 2); +assert.equal(arr_buff4.toString('hex'), '2a2b'); diff --git a/test/run_pass/test_buffer_inmutability_creation.js b/test/run_pass/test_buffer_inmutability_creation.js new file mode 100644 index 0000000000..94dcfb152e --- /dev/null +++ b/test/run_pass/test_buffer_inmutability_creation.js @@ -0,0 +1,41 @@ +/* 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. + */ + +/* Related issue: https://github.com/Samsung/iotjs/issues/1379 */ + +var assert = require('assert'); + +/* The global Buffer by default is a function */ +assert.strictEqual(typeof(Buffer), "function"); + +var backup_buffer = Buffer; + +/* Modify the global Buffer */ +Buffer++; + +/** + * The ++ operation will change the value of the "Buffer" variable. + * Thus the type shouldn't be a function now. + */ +assert.notStrictEqual(typeof(Buffer), "function"); + +/** + * Still the creation of buffer should work. + * Using an already saved buffer reference + */ +var new_buffer = backup_buffer("OK"); + +assert.equal(new_buffer.length, 2); +assert.equal(new_buffer.toString(), "OK"); diff --git a/test/run_pass/test_buffer_str_conv.js b/test/run_pass/test_buffer_str_conv.js new file mode 100644 index 0000000000..7aeae86d27 --- /dev/null +++ b/test/run_pass/test_buffer_str_conv.js @@ -0,0 +1,100 @@ +/* Copyright 2015-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'); + +function decodeError(string, encode) +{ + try { + new Buffer(string, encode); + } catch (e) { + assert.assert(e instanceof TypeError); + } +} + +function testWrite(input, string, offset, length, + encoding, expected, expectedLength) +{ + var buf = new Buffer(input); + + assert.equal(buf.write(string, offset, length, encoding), expectedLength); + assert.equal(buf.toString(), expected); +} + +/* Base64 tests. */ + +assert.equal((new Buffer('YnVmZg==', 'base64')).toString(), 'buff'); +assert.equal((new Buffer('YnVmZmU=', 'base64')).toString(), 'buffe'); +assert.equal((new Buffer('YnVmZmVy', 'base64')).toString(), 'buffer'); +assert.equal((new Buffer('KiAxMjM0ICo=', 'base64')).toString(), '* 1234 *'); +assert.equal((new Buffer('f39/fw==', 'base64')).toString(), + '\u007f\u007f\u007f\u007f'); +assert.equal((new Buffer('fn5+fg==', 'base64')).toString(), + '\u007e\u007e\u007e\u007e'); + +decodeError('Yn=mZg==', 'base64'); +decodeError('YnVmZ===', 'base64'); +decodeError('YnVmZm', 'base64'); +decodeError('KiAx*jM0ICo=', 'base64'); + +testWrite('xxxxxxxx', 'MTIzNA==', 2, 16, 'base64', 'xx1234xx', 4); +testWrite('xxxxxxxx', 'MTIzNA==', 2, 0, 'base64', 'xxxxxxxx', 0); +testWrite('xxxxxxxx', 'MTIzNA==', 3, 2, 'base64', 'xxx12xxx', 2); +testWrite('xxxx', 'MTIzNA==', 2, 16, 'base64', 'xx12', 2); + +assert.throws(function () { + /* Malformed string must throw error regardless of the buffer length. */ + testWrite('xxxxxxxx', 'MTIzNA=!', 2, 2, 'base64', 'xx12xxxx'); +}); + + +assert.equal((new Buffer('buff')).toString('base64'), 'YnVmZg=='); +assert.equal((new Buffer('buffe')).toString('base64'), 'YnVmZmU='); +assert.equal((new Buffer('buffer')).toString('base64'), 'YnVmZmVy'); +assert.equal((new Buffer('\u007f\u007f\u007f\u007f')).toString('base64'), + 'f39/fw=='); +assert.equal((new Buffer('\u007e\u007e\u007e\u007e')).toString('base64'), + 'fn5+fg=='); + +assert.equal((new Buffer('**buffer**')).toString('base64', 2, 7), 'YnVmZmU='); + + +/* Hex tests. */ + +assert.equal((new Buffer('6768696A6b6c6D6e6f70', 'hex')).toString(), + 'ghijklmnop'); +assert.equal((new Buffer('2a20427546663352202a', 'hex')).toString(), + '* BuFf3R *'); +assert.equal((new Buffer('eFbfBf', 'hex')).toString(), '\uffff'); + +decodeError('0*12', 'hex'); +decodeError('0fe', 'hex'); +decodeError('0g', 'hex'); + +testWrite('xxxxxxxx', '31323334', 2, 16, 'hex', 'xx1234xx', 4); +testWrite('xxxxxxxx', '31323334', 2, 0, 'hex', 'xxxxxxxx', 0); +testWrite('xxxxxxxx', '31323334', 3, 2, 'hex', 'xxx12xxx', 2); +testWrite('xxxx', '31323334', 2, 16, 'hex', 'xx12', 2); + +assert.throws(function () { + /* Malformed string must throw error regardless of the buffer length. */ + testWrite('xxxxxxxx', '3132333g', 2, 2, 'base64', 'xx12xxxx'); +}); + +assert.equal((new Buffer('ghijklmnop')).toString('hex'), + '6768696a6b6c6d6e6f70'); + +assert.equal((new Buffer('ghijklmnop')).toString('hex', 2, 8), + '696a6b6c6d6e'); diff --git a/test/run_pass/test_console.js b/test/run_pass/test_console.js index 437dc244a7..ab4810d425 100644 --- a/test/run_pass/test_console.js +++ b/test/run_pass/test_console.js @@ -24,6 +24,7 @@ console.log([1, 2, 3]); console.log(1, 2, 3); console.log('a', 1, 'b', 2, 'c', 3); console.log("test", null, undefined); +console.log({ a: '123', b: 123, c: [1, 2, 3]}); console.error("Hello IoT.js!!"); console.error(1); diff --git a/test/run_pass/test_crypto.js b/test/run_pass/test_crypto.js new file mode 100644 index 0000000000..478224071e --- /dev/null +++ b/test/run_pass/test_crypto.js @@ -0,0 +1,32 @@ +/* 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 crypto = require('crypto'); +var assert = require('assert'); + +var hash = crypto.createHash('sha1'); + +assert.throws(function() { var err_hash = crypto.createHash('sadf'); }); + +hash.update('Hello IoT.js'); + +assert.equal(hash.digest('hex'), '4f5cf1945efb60f400c23172edb4e36b47f5a25e'); +assert.throws(function() { hash.digest('hex'); }); + +var hash2 = crypto.createHash('sha1'); +hash2.update('Hello IoT.js'); +hash2.update(' v2'); + +assert.equal(hash2.digest('base64'), 'DBnLTkxZ70AgUzCjZ7FTv91AWZw='); diff --git a/test/run_pass/test_crypto_tls.js b/test/run_pass/test_crypto_tls.js new file mode 100644 index 0000000000..2f11f65288 --- /dev/null +++ b/test/run_pass/test_crypto_tls.js @@ -0,0 +1,66 @@ +/* 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 assert = require('assert'); +var crypto = require('crypto'); +var fs = require('fs'); + +var hash = crypto.createHash('sha256'); +hash.update('Hello IoT.js'); + +assert.equal(hash.digest('hex'), + '23a1b938002c83a74b887d0a447c990' + + '5e83bab00459bcfd0bad548623b942e20'); + +/* + This test requires a key file, which can be generated using the following + steps: + openssl genrsa -aes128 -passout pass: -out private.pem 2048 + openssl rsa -in private.pem -passin pass: -pubout -out public.pem + + Recreating this test with your own data requires you to have (a) key file(s) + with a public and a private key in them. The private key is used to sign the + data. + The public key is used to verify that the signature was done with the + appropriate private key. + + To generate the rsa-sha256 signature you need to execute these lines: + Creating an sha256 signature + openssl dgst -sha256 -sign -out + Creating a base64 encoded signature + openssl base64 -in -out + + To verify the signature, you need: + - The file, + - The public key, most likely from the public.pem file, + - The which contains the data, or you can just copy and paste, + the data and give it to the `verify.update()` function. + + Having created the `verify` object, just call the `.verify(pubkey, signature)` + on it, and you are ready to go. +*/ + +var pubKey = fs.readFileSync(process.cwd() + '/resources/crypto_public.pem'); +var verify = crypto.createVerify('sha256'); +verify.update('Hello IoT.js\n'); +var res = verify.verify(pubKey, 'JkFnOrBQGXYlpmlcMuS5EwyJ44WY/kW5sFwb8DRgAoo7' + + 'RmxYPKgyo/OrZ0YAcY5xpxbVZzS7ftxz7N4q+Ouufg6s' + + 'NSzmIimBPLV+afX4Qb8jOV0edCmeBKZaHQrMWpisWXF/' + + 'bZKS1yiMij2NGSJYXWhjRzreIeVNVv/b0phHHeK2r2tT' + + '9T+XA+rdgHlIOb+r/FT/VWopr+vd+8I0fjxpP/S8lZ5u' + + 'HSF9jZ5TFdIEYMWchKit4Eyw7/VAWRlJNNKVxTmuM337' + + '+rP9oLKiFUeoM6jrE10LxGnIpelvyNV+MHfo11I1GAMK' + + 'jsOuye9JZ8/hQPg+KLWH/l/xZlUD2fZNNg=='); +assert.equal(res, true); diff --git a/test/run_pass/test_dgram_1_server_n_clients.js b/test/run_pass/test_dgram_1_server_n_clients.js index 8373188de5..5d0684628b 100644 --- a/test/run_pass/test_dgram_1_server_n_clients.js +++ b/test/run_pass/test_dgram_1_server_n_clients.js @@ -41,30 +41,32 @@ server.on('message', function(data, rinfo) { server.bind(port); -for (var i = 0; i < sockcount; i++) { - (function sendAndRecieve(i) { - var client = dgram.createSocket('udp4'); +function sendAndRecieve(i) { + var client = dgram.createSocket('udp4'); + + client.send(i.toString(), port, 'localhost'); - client.send(i.toString(), port, 'localhost'); + client.on('error', function(err) { + assert.fail(); + client.close(); + }); - client.on('error', function(err) { - assert.fail(); - client.close(); - }); + client.on('message', function(data, rinfo) { + console.log('client got data : ' + data); + assert.equal(port, rinfo.port); + assert.equal(data, i.toString()); + client.close(); + }); +} - client.on('message', function(data, rinfo) { - console.log('client got data : ' + data); - assert.equal(port, rinfo.port); - assert.equal(data, i.toString()); - client.close(); - }); - })(i); +for (var i = 0; i < sockcount; i++) { + setTimeout(sendAndRecieve, 200 * i, i); } process.on('exit', function(code) { assert.equal(msg.length, sockcount); for (var i = 0; i < sockcount; i++) { - if (msg.indexOf(i.toString()) == -1) { + if (msg.indexOf(i.toString()) === -1) { assert.fail(); } } diff --git a/test/run_pass/test_dgram_multicast_membership.js b/test/run_pass/test_dgram_multicast_membership.js index fff837a76d..f998a5011d 100644 --- a/test/run_pass/test_dgram_multicast_membership.js +++ b/test/run_pass/test_dgram_multicast_membership.js @@ -15,49 +15,74 @@ var assert = require('assert'); var dgram = require('dgram'); +var MODE = process.argv[2] || 'echo'; +var SERVER = 'server'; +var CLIENT = 'client'; +var ECHO = 'echo'; + +if (MODE !== 'server' && MODE !== 'client' && MODE !== 'echo') { + console.log( + 'usage: iotjs test_dgram_multicast_membership.js server|client|echo'); + assert(false); +} var port = 41239; var multicast_address = '230.255.255.250'; -var interval = 100; +var interval = 1000; +var msg = 'Hello IoT.js'; -var recv_count = 0, send_count = 0; +if (MODE !== CLIENT) { // for server and echo + var recv_count = 0; + var server = dgram.createSocket('udp4'); -var msg = 'Hello IoT.js'; -var client = dgram.createSocket('udp4'); -var server = dgram.createSocket('udp4'); + server.on('message', function(data, rinfo) { + console.log('server got data : ' + data); + recv_count++; + if (recv_count == 1) { + server.dropMembership(multicast_address); + } + }); -server.on('error', function(err) { - assert.fail(); - server.close(); -}); + server.bind(port, function() { + server.addMembership(multicast_address); + }); -server.on('message', function(data, rinfo) { - console.log('server got data : ' + data); - recv_count++; - if (recv_count == 1) { - server.dropMembership(multicast_address); - } -}); + server.on('error', function(err) { + assert.fail(); + server.close(); + }); -server.bind(port, function() { - server.addMembership(multicast_address); -}); + setTimeout(function() { + server.close(); + }, 5000); +} -var timer = setInterval(function () { - send_count++; - client.send(msg, port, multicast_address); - if (send_count == 3) { - clearInterval(timer); - } -}, interval); +if (MODE !== SERVER) { // for client and echo + var send_count = 0; + var client = dgram.createSocket('udp4'); + + var timer = setInterval(function () { + send_count++; + + console.log('client send data : ' + msg); + client.send(msg, port, multicast_address); + if (send_count == 3) { + clearInterval(timer); + } + }, interval); -setTimeout(function() { - server.close(); - client.close(); -}, 1000); + setTimeout(function() { + client.close(); + }, 5000); +} process.on('exit', function(code) { assert.equal(code, 0); - assert.equal(recv_count, 1); - assert.equal(send_count, 3); + + if (MODE !== CLIENT) { + assert.equal(recv_count, 1); + } + if (MODE !== SERVER) { + assert.equal(send_count, 3); + } }); diff --git a/test/run_pass/test_dgram_setttl_client.js b/test/run_pass/test_dgram_setttl_client.js index 6e91bd4cb8..5e64047fbd 100644 --- a/test/run_pass/test_dgram_setttl_client.js +++ b/test/run_pass/test_dgram_setttl_client.js @@ -18,6 +18,7 @@ var dgram = require('dgram'); var port = 41234; var msg = 'Hello IoT.js'; +var msg2 = 'Bye IoT.js'; var addr = '192.168.0.1'; // Change to your ip address var server = dgram.createSocket('udp4'); @@ -33,7 +34,7 @@ client.on('error', function(err) { }); client.on('listening', function(err) { - client.setTTL(1); + client.setTTL(2); }); client.on('message', function(data, rinfo) { @@ -43,6 +44,16 @@ client.on('message', function(data, rinfo) { console.log('server family : ' + rinfo.family); assert.equal(port, rinfo.port); assert.equal(data, msg); - client.close(); + /* send with TTL=1 */ + client.setTTL(1); + client.send(msg2, port, addr, function(err, len) { + assert.equal(err, null); + assert.equal(len, msg2.length); + client.close(); + }); +}); + +process.on('exit', function(code) { + assert.equal(code, 0); }); diff --git a/test/run_pass/test_dgram_setttl_server.js b/test/run_pass/test_dgram_setttl_server.js index b71bade209..296f4e69f1 100644 --- a/test/run_pass/test_dgram_setttl_server.js +++ b/test/run_pass/test_dgram_setttl_server.js @@ -19,6 +19,8 @@ var dgram = require('dgram'); var port = 41234; var msg = 'Hello IoT.js'; var server = dgram.createSocket('udp4'); +var recvMsg = ""; +var recvCnt = 0; server.on('error', function(err) { assert.fail(); @@ -30,21 +32,24 @@ server.on('message', function(data, rinfo) { console.log('client address : ' + rinfo.address); console.log('client port : ' + rinfo.port); console.log('client family : ' + rinfo.family); - assert.equal(data, msg); + recvMsg = data; + recvCnt++; server.send(msg, rinfo.port, rinfo.address, function (err, len) { assert.equal(err, null); assert.equal(len, msg.length); }); + setTimeout(function() { server.close() }, 4000); }); + server.on('listening', function() { console.log('listening'); }); -server.bind(port, function() { - server.setTTL(1); -}); +server.bind(port); process.on('exit', function(code) { assert.equal(code, 0); + assert.equal(recvCnt, 1); + assert.equal(recvMsg, msg); }); diff --git a/test/run_pass/test_dns_lookup.js b/test/run_pass/test_dns_lookup.js index f225b86488..d5a4ac0ad5 100644 --- a/test/run_pass/test_dns_lookup.js +++ b/test/run_pass/test_dns_lookup.js @@ -54,13 +54,18 @@ dns.lookup('localhost', function(err, ip, family) { // Test with invalid hostname. dns.lookup('invalid', 4, function(err, ip, family) { assert.notEqual(err, null); - assert.equal(err.code == -3008 || err.code == -3007, true); }); // Test with empty hostname. dns.lookup('', 4, function(err, ip, family) { - assert.notEqual(err, null); - assert.equal(err.code == -3008 || err.code == -3007, true); + if (process.platform === "windows") { + /* On windows the empty dns name can be resolved. */ + assert.equal(err, null); + assert.notEqual(ip, null); + assert.notEqual(family, null); + } else { + assert.notEqual(err, null); + } }); // Test with non string hostname. diff --git a/test/run_pass/test_events.js b/test/run_pass/test_events.js index 71a4da408d..feb2aadf80 100644 --- a/test/run_pass/test_events.js +++ b/test/run_pass/test_events.js @@ -13,9 +13,10 @@ * limitations under the License. */ -var EventEmitter = require('events').EventEmitter; +var EventEmitter = require('events'); var assert = require('assert'); +assert.strictEqual(EventEmitter, EventEmitter.EventEmitter); var emitter = new EventEmitter(); diff --git a/test/run_pass/test_events_uncaught_error.js b/test/run_pass/test_events_uncaught_error.js index 0eb61a6f57..e012c7c49f 100644 --- a/test/run_pass/test_events_uncaught_error.js +++ b/test/run_pass/test_events_uncaught_error.js @@ -21,14 +21,15 @@ var EventEmitter = require('events').EventEmitter; var uncaught_error = false; process.on('uncaughtException', function(err) { - assert.equal(err.message, "Uncaught 'error' event"); + assert.equal(err.message, "Uncaught 'error' event", + 'Error type does not match'); uncaught_error = true; }); process.on('exit', function(code) { process.removeAllListeners('uncaughtException'); - assert.equal(code, 0); - assert(uncaught_error); + assert.equal(code, 0, 'Non-zero exit status code:' + code); + assert(uncaught_error, 'Expected uncaughtException was not executed'); }); var ee = new EventEmitter(); diff --git a/test/run_pass/test_fs_event.js b/test/run_pass/test_fs_event.js index 5bc4822679..20b49f10c4 100644 --- a/test/run_pass/test_fs_event.js +++ b/test/run_pass/test_fs_event.js @@ -14,7 +14,6 @@ */ - var fs = require('fs'); var assert = require('assert'); @@ -22,46 +21,55 @@ var assert = require('assert'); var srcFilePath = process.cwd() + "/resources/test1.txt"; var dstFilePath = process.cwd() + "/tmp/test_fs2.txt"; -var data; +// TizenRT tests are performed from ROM +// Files should be stored in other path +if (process.platform === 'tizenrt') { + dstFilePath = "/mnt/test_fs2.txt"; -function onWrite(err, written, buffer) { - if (err) { - throw err; - } else { - var fd = fs.openSync(dstFilePath, 'r'); - var buffer = new Buffer(128); - fs.readSync(fd, buffer, 0, buffer.length, 0); - - var result = 'TEST File Read & Write\n'; + // Prepare test environment + if (fs.existsSync(dstFilePath)) { + fs.unlinkSync(dstFilePath); + } +} - assert.equal(buffer.toString(), result); +function cleanup() { + if (process.platform === 'tizenrt') { + fs.unlinkSync(dstFilePath); } } +var result = 'TEST File Read & Write\n'; +var data; + function onOpenForWrite(err, fd) { - if (err) { - throw err; - } else { - fs.write(fd, data, 0, data.length, onWrite); - } + assert.equal(err, null, 'Failed to open for write file:' + err); + + fs.write(fd, data, 0, data.length, function (err, written, buffer) { + assert.equal(err, null, 'Failed to write file:' + err); + fs.closeSync(fd); + + var fdr = fs.openSync(dstFilePath, 'r'); + var buffer = new Buffer(128); + fs.readSync(fdr, buffer, 0, buffer.length, 0); + fs.closeSync(fdr); + + cleanup(); + + assert.equal(buffer.toString(), result, + 'Read/write content does not match'); + }); } function onRead(err, bytesRead, buffer) { - if (err) { - throw err; - } else { - data = new Buffer(buffer.toString()); - fs.open(dstFilePath, 'w', onOpenForWrite); - } + assert.equal(err, null, 'Failed to read file:' + err); + data = new Buffer(buffer.toString()); + fs.open(dstFilePath, 'w', onOpenForWrite); } function onOpenForRead(err, fd) { - if (err) { - throw err; - } else { - var buffer = new Buffer(128); - fs.read(fd, buffer, 0, buffer.length, 0, onRead); - } + assert.equal(err, null, 'Failed to open for read file:' + err); + var buffer = new Buffer(128); + fs.read(fd, buffer, 0, buffer.length, 0, onRead); } fs.open(srcFilePath, 'r', onOpenForRead); diff --git a/test/run_pass/test_fs_exists.js b/test/run_pass/test_fs_exists.js index e380bafa8b..bcb6575d9c 100644 --- a/test/run_pass/test_fs_exists.js +++ b/test/run_pass/test_fs_exists.js @@ -17,49 +17,55 @@ var fs = require('fs'); var assert = require('assert'); { - var filePath = process.cwd() + "/resources/tobeornottobe.txt"; + var filePath = process.cwd() + '/resources/tobeornottobe.txt'; fs.exists(filePath, function(exists) { - assert.equal(exists, true); + assert.equal(exists, true, 'File should exist: ' + filePath); }); } { - var filePath = ""; + var filePath = ''; - assert.doesNotThrow(function(){ + assert.doesNotThrow(function() { + fs.exists(filePath, function (exists) { + assert.equal(exists, false, 'File with empty name should not exist'); + }); + }, 'Checking fs.exists(\'\') without callback does not throw exception'); + + assert.doesNotThrow(function() { fs.exists(filePath); - }); + }, 'Checking fs.exists(\'\') without callback does not throw exception'); } { - var filePath = process.cwd() + "/resources/tobeornottobe.txt"; + var filePath = process.cwd() + '/resources/tobeornottobe.txt'; - assert.doesNotThrow(function(){ + assert.doesNotThrow(function() { fs.exists(filePath); - }); + }, 'Checking fs.exists() for existing file does not throw exception'); } { - var filePath = process.cwd() + "/resources/empty.txt"; + var filePath = process.cwd() + '/resources/empty.txt'; fs.exists(filePath, function(exists) { - assert.equal(exists, false); + assert.equal(exists, false, 'File should not exist' + filePath); }); } { - var filePath = ""; + var filePath = ''; fs.exists(filePath, function(exists) { - assert.equal(exists, false); + assert.equal(exists, false, 'File with empty name should not exist'); }); } { - var filePath = " "; + var filePath = ' '; fs.exists(filePath, function(exists) { - assert.equal(exists, false); + assert.equal(exists, false, 'File name with single whitespace check'); }); } diff --git a/test/run_pass/test_fs_exists_sync.js b/test/run_pass/test_fs_exists_sync.js index 7aa2f1bdc1..a1deeac819 100644 --- a/test/run_pass/test_fs_exists_sync.js +++ b/test/run_pass/test_fs_exists_sync.js @@ -20,26 +20,26 @@ var assert = require('assert'); var filePath = process.cwd() + "/resources/tobeornottobe.txt"; var result = fs.existsSync(filePath); - assert.equal(result, true); + assert.equal(result, true, 'File should exist: ' + filePath); } { var filePath = process.cwd() + "/resources/empty.txt"; var result = fs.existsSync(filePath); - assert.equal(result, false); + assert.equal(result, false, 'File should not exist: ' + filePath); } { var filePath = ""; var result = fs.existsSync(filePath); - assert.equal(result, false); + assert.equal(result, false, 'File with empty should not exist'); } { var filePath = " "; var result = fs.existsSync(filePath); - assert.equal(result, false); + assert.equal(result, false, 'File name with single whitespace check'); } diff --git a/test/run_pass/test_fs_mkdir_rmdir.js b/test/run_pass/test_fs_mkdir_rmdir.js index b7e4d6d5ec..ee167b7c5e 100644 --- a/test/run_pass/test_fs_mkdir_rmdir.js +++ b/test/run_pass/test_fs_mkdir_rmdir.js @@ -16,6 +16,14 @@ var fs = require('fs'); var assert = require('assert'); +var testRoot = process.cwd() + "/resources"; + +// TizenRT tests are performed from ROM +// Files should be stored in other path +if (process.platform === 'tizenrt') { + testRoot = "/mnt"; +} + function unlink(path) { try { fs.rmdirSync(path); @@ -25,9 +33,9 @@ function unlink(path) { } { - var root = process.cwd() + "/resources/test_dir"; - var sub1 = process.cwd() + "/resources/test_dir/file1"; - var sub2 = process.cwd() + "/resources/test_dir/file2"; + var root = testRoot + "/test_dir"; + var sub1 = root + "/file1"; + var sub2 = root + "/file2"; unlink(sub1); unlink(sub2); @@ -46,40 +54,33 @@ function unlink(path) { fs.rmdir(root, function() { assert.equal(fs.existsSync(root), false); - }); - - var root2 = process.cwd() + "/resources/test_dir2"; + var root2 = testRoot + "/test_dir2"; - fs.mkdir(root2, 777, function(err) { - assert.equal(err, null); - assert.equal(fs.existsSync(root2), true); + fs.mkdir(root2, 777, function(err) { + assert.equal(err, null); + assert.equal(fs.existsSync(root2), true); - fs.rmdir(root2, function(){ - assert.equal(fs.existsSync(root2), false); - }); + fs.rmdir(root2, function() { + assert.equal(fs.existsSync(root2), false); + }); - // Run read-only directory test only on linux - // NuttX does not support read-only attribute. - if (process.platform === 'linux') { - // Try to create a folder in a read-only directory. - fs.mkdir(root, '0444', function(err) { - assert.equal(fs.existsSync(root), true); + // Run read-only directory test only on linux and Tizen + // NuttX does not support read-only attribute. + if (process.platform === 'linux' || process.platform === 'tizen') { + var testMode = '0444'; + fs.mkdir(root, testMode, function(err) { + assert.equal(err, null); + assert.equal(fs.existsSync(root), true); - var dirname = root + "/permission_test"; - try { - fs.mkdirSync(dirname); - assert.assert(false); - } catch (e) { - assert.equal(e instanceof Error, true); - assert.equal(e instanceof assert.AssertionError, false); - } + var mode = fs.statSync(root).mode; + assert.strictEqual(mode.toString(8).slice(-4), testMode); - assert.equal(fs.existsSync(dirname), false); - fs.rmdir(root, function() { - assert.equal(fs.existsSync(root), false); + fs.rmdir(root, function() { + assert.equal(fs.existsSync(root), false); + }); }); - }); - } + } + }); }); }); } diff --git a/test/run_pass/test_fs_open_close.js b/test/run_pass/test_fs_open_close.js index 528408107f..086b4fd672 100644 --- a/test/run_pass/test_fs_open_close.js +++ b/test/run_pass/test_fs_open_close.js @@ -14,134 +14,121 @@ */ - var fs = require('fs'); var assert = require('assert'); - -var fileName = process.cwd() + "/resources/greeting.txt"; - +var fileName = process.cwd() + '/resources/greeting.txt'; // test sync open & close. // test normal sequence. -try { +assert.doesNotThrow(function() { var fd = fs.openSync(fileName, 'r'); + assert.notEqual(fs, null, 'Error opening file: ' + fileName); fs.closeSync(fd); -} catch (err) { - throw err; -} +}, 'Test normal sequence. Open file for reading'); // test trying to open not exist file - expecting exception. -try { +assert.throws(function() { var fd = fs.openSync('not_exist_file', 'r'); - assert.fail('none', 'exception'); -} catch (err) { -} +}, Error, 'Test trying to openSync not exist file - expecting exception'); // test trying to close with bad fd - expecting exception. -try { +assert.throws(function() { fs.closeSync(-1); - assert.fail('none', 'exception'); -} catch (err) { -} - +}, Error, 'Test trying to close with bad fd - expecting exception'); // test async open & close. // test normal sequence. -var fs_async_normal_ok = false; fs.open(fileName, 'r', function(err, fd) { - if (err) { - throw err; - } else { - fs.close(fd, function(err) { - if (err) { - throw err; - } else { - fs_async_normal_ok = true; - } - }); - } + assert.equal(err, null, + 'Async Normal: Error opening ' + fileName + ': ' + err); + + fs.close(fd, function(err) { + assert.equal(err, null, + 'Async Normal: Error closing ' + fileName + ': ' + err); + }); }); // test not exist file - expecting exception. -var fs_async_open_not_exist_ok = false; fs.open('not_exist_file', 'r', function(err, fd) { - if (err) { - fs_async_open_not_exist_ok = true; - } else { - assert.fail('none', 'exception'); - } + assert.notEqual(err, null, 'Test not exist file - expecting exception'); }); // test trying to close with bad fd - expecting exception. -var fs_async_close_bad_fd_ok = false; fs.close(-1, function(err) { - if (err) { - fs_async_close_bad_fd_ok = true; - } else { - assert.fail('none', 'exception'); - } + assert.notEqual(err, null, + 'Test trying to close with bad fd - expecting exception'); }); -var buffer = new Buffer(10); -// expect length out of bound -assert.throws(function () { fs.readSync(5, buffer, 0, 20); }, RangeError); -// expect offset out of bound -assert.throws(function () { fs.readSync(5, buffer, -1, 20); }, RangeError); - -var fs_async_normal_ok2 = false; -fs.open(fileName, 'r', '4' ,function(err, fd) { - if (err) { - throw err; - } else { - fs.close(fd, function(err) { - if (err) { - throw err; - } else { - fs_async_normal_ok2 = true; - } - }); - } -}); +{ + var buffer = new Buffer(10); + // expect length out of bound + assert.throws(function () { fs.readSync(5, buffer, 0, 20); }, RangeError, + 'Expect length out of bound 0, 20'); + // expect offset out of bound + assert.throws(function () { fs.readSync(5, buffer, -1, 20); }, RangeError, + 'Expect length out of bound -1, 20'); +} -process.on('exit', function() { - assert.equal(fs_async_normal_ok, true); - assert.equal(fs_async_normal_ok2, true); - assert.equal(fs_async_open_not_exist_ok, true); - assert.equal(fs_async_close_bad_fd_ok, true); -}); +fs.open(fileName, 'r', '4' , function(err, fd) { + assert.equal(err, null, + 'Async Normal2: Error opening ' + fileName + ': ' + err); + fs.close(fd, function(err) { + assert.equal(err, null, + 'Async Normal2: Error closing ' + fileName + ': ' + err); + }); +}); -assert.throws (function() { +assert.throws(function() { var fd = fs.openSync(null, 123); - }, TypeError); -assert.throws (function() { +}, TypeError, 'Calling fs.openSync with null file path'); +assert.throws(function() { var fd = fs.openSync(process.cwd() + '/run_pass/test_fs_stat.js', 'k'); -}, TypeError); -assert.throws (function() { +}, TypeError, 'Calling fs.openSync with invalid flag'); +assert.throws(function() { var fd = fs.openSync(process.cwd() + '/resources/test2.txt', null); -}, TypeError); +}, TypeError, 'Calling fs.openSync with null flag'); + + +var testRoot = process.cwd() + '/resources'; +var readFile = testRoot + '/test2.txt'; + +// TizenRT tests are performed from ROM +// Files should be stored in other path +if (process.platform === 'tizenrt') { + testRoot = '/mnt'; + readFile = testRoot + '/test2.txt'; + + // Create file for read test + fs.closeSync(fs.openSync(readFile, 'w')); +} ('rs sr r+ rs+ sr+ a a+') - .split(' ').forEach(function (flag){ - assert.doesNotThrow(function (){ - var fd = fs.openSync(process.cwd() + '/resources/test2.txt', flag); + .split(' ').forEach(function (flag) { + assert.doesNotThrow(function () { + var fd = fs.openSync(readFile, flag); fs.closeSync(fd); - }, 'file could not be opened with ' + flag); + }, 'File could not be opened with flag: ' + flag); }); +// Cleanup after test +if (process.platform === 'tizenrt') { + fs.unlinkSync(readFile); +} + ('wx xw w+ wx+ xw+ ax+ xa+ ax xa') - .split(' ').forEach(function (flag){ - assert.doesNotThrow(function(){ - var file = process.cwd() + '/resources/TEMP' + flag + '.txt'; + .split(' ').forEach(function (flag) { + assert.doesNotThrow(function() { + var file = testRoot + '/TEMP' + flag + '.txt'; var fd = fs.openSync(file, flag); - fs.unlinkSync(file); fs.closeSync(fd); - }, 'file could not be opened with ' + flag); + fs.unlinkSync(file); + }, 'File could not be opened with flag: ' + flag); }); diff --git a/test/run_pass/test_fs_open_read_sync_1.js b/test/run_pass/test_fs_open_read_sync_1.js index 57ea947cb2..1500c8e07d 100644 --- a/test/run_pass/test_fs_open_read_sync_1.js +++ b/test/run_pass/test_fs_open_read_sync_1.js @@ -22,6 +22,12 @@ var assert = require('assert'); var srcFilePath = process.cwd() + "/resources/test1.txt"; var dstFilePath = process.cwd() + "/tmp/test_fs1.txt"; +// TizenRT tests are performed from ROM +// Files should be stored in other path +if (process.platform === 'tizenrt') { + dstFilePath = "/mnt/test_fs1.txt"; +} + try { var fd1 = fs.openSync(srcFilePath, 'r'); var buffer = new Buffer(128); diff --git a/test/run_pass/test_fs_read_stream.js b/test/run_pass/test_fs_read_stream.js new file mode 100644 index 0000000000..5e43e675b4 --- /dev/null +++ b/test/run_pass/test_fs_read_stream.js @@ -0,0 +1,70 @@ +/* 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 fs = require('fs'); +var assert = require('assert'); + +if (fs.createReadStream === undefined || fs.createWriteStream === undefined) { + process.exit(0); +} + +var inputFile = process.cwd() + '/resources/tobeornottobe.txt'; + +var res; +var expected = + "To be, or not to be, that is the Question:\n" + + "Whether ’tis Nobler in the mind to ſuffer\n" + + "The Slings and Arrows of outragious Fortune,\n" + + "Or to take Armes against a Sea of troubles,\n" + + "And by opposing end them: to dye, to ſleepe\n" + + "No more; and by a sleep, to say we end\n" + + "The Heart-ake, and the thouſand Naturall ſhockes\n" + + 'That Flesh is there too? "Tis a consummation\n' + + "Deuoutly to be wiſh'd. To dye to sleepe,\n" + + "To sleep, perchance to Dream; I, there's the rub,\n" + + "For in that sleep of death, what dreams may come,\n" + + "When we haue ſhufflel’d off this mortall coile,\n" + + "Muſt giue us pause. There's the respect\n" + + "That makes Calamity of long life:\n" + + "For who would beare the Whips and Scornes of time,\n" + + "The Oppreſſors wrong, the poore mans Contumely,\n" + + "The pangs of diſpriz’d Loue, the Lawes delay,\n" + + "The inſolence of Office, and the Spurnes\n" + + "That patient merit of the vnworthy takes,\n" + + "When he himſelfe might his Quietus make\n" + + "With a bare Bodkin? Who would theſe Fardles beare\n" + + "To grunt and ſweat vnder a weary life,\n" + + "But that the dread of ſomething after death,\n" + + "The vndiſcouered Countrey, from whoſe Borne\n" + + "No Traueller returnes, Puzels the will,\n" + + "And makes vs rather beare those illes we haue,\n" + + "Then flye to others that we know not of.\n" + + "Thus Conſcience does make Cowards of vs all,\n" + + "And thus the Natiue hew of Resolution\n" + + "Is ſicklied o’re, with the pale caſt of Thought,\n" + + "And enterprizes of great pith and moment,\n" + + "With this regard their Currants turne away,\n" + + "And looſe the name of Action. Soft you now,\n" + + "The faire Ophelia? Nimph, in thy Orizons\n" + + "Be all my ſinnes remembred."; + +var readableFileStream = fs.createReadStream(inputFile); + +readableFileStream.on('data', function(data) { + res = data; +}); + +process.on('exit', function() { + assert.equal(res, expected); +}); diff --git a/test/run_pass/test_fs_readdir.js b/test/run_pass/test_fs_readdir.js index d826d2d0ae..3b842e9640 100644 --- a/test/run_pass/test_fs_readdir.js +++ b/test/run_pass/test_fs_readdir.js @@ -23,7 +23,7 @@ var ans = 'DO_NOT_MODIFY_THIS_FOLDER\n'+ 'regular.txt\n'; var res; -var items; +var items, i; res = ""; items = fs.readdirSync(path); diff --git a/test/run_pass/test_fs_rename.js b/test/run_pass/test_fs_rename.js index 27778f3775..e8d0a0c8b1 100644 --- a/test/run_pass/test_fs_rename.js +++ b/test/run_pass/test_fs_rename.js @@ -20,15 +20,32 @@ var fs = require('fs'); var assert = require('assert'); -var file1 = process.cwd() + "/resources/rename.txt"; -var file2 = process.cwd() + "/resources/rename.txt.async"; +var file1 = process.cwd() + '/resources/rename.txt'; +var file2 = process.cwd() + '/resources/rename.txt.async'; + +// TizenRT tests are performed from ROM +// Files should be stored in other path +if (process.platform === 'tizenrt') { + file1 = '/mnt/rename.txt'; + file2 = '/mnt/rename.txt.sync'; + + fs.closeSync(fs.openSync(file1, 'w')); +} + +assert.equal(fs.existsSync(file1), true, + 'Test prerequisites: checking existance of ' + file1); fs.rename(file1, file2, function(err) { - assert.equal(err, null); - assert.equal(fs.existsSync(file1), false); - assert.equal(fs.existsSync(file2), true); + assert.equal(err, null, 'Rename error:' + err); + assert.equal(fs.existsSync(file1), false, 'Source file exist after renaming'); + assert.equal(fs.existsSync(file2), true, + 'Destination file not exist after renaming'); fs.rename(file2, file1, function(err) { - assert.equal(err, null); - console.log("Pass"); + assert.equal(err, null, 'Renaming back error: ' + err); + + // Cleanup after test + if (process.platform === 'tizenrt') { + fs.unlinkSync(file1); + } }); }); diff --git a/test/run_pass/test_fs_rename_sync.js b/test/run_pass/test_fs_rename_sync.js index 363fe563ed..56d5d2fb20 100644 --- a/test/run_pass/test_fs_rename_sync.js +++ b/test/run_pass/test_fs_rename_sync.js @@ -16,10 +16,28 @@ var fs = require('fs'); var assert = require('assert'); -var file1 = process.cwd() + "/resources/rename.txt"; -var file2 = process.cwd() + "/resources/rename.txt.sync"; +var file1 = process.cwd() + '/resources/rename.txt'; +var file2 = process.cwd() + '/resources/rename.txt.sync'; + +// TizenRT tests are performed from ROM +// Files should be stored in other path +if (process.platform === 'tizenrt') { + file1 = '/mnt/rename.txt'; + file2 = '/mnt/rename.txt.sync'; + + fs.closeSync(fs.openSync(file1, 'w')); +} + +assert.equal(fs.existsSync(file1), true, + 'Test prerequisites: checking existance of ' + file1); fs.renameSync(file1, file2); -assert.equal(fs.existsSync(file1), false); -assert.equal(fs.existsSync(file2), true); +assert.equal(fs.existsSync(file1), false, 'Source file exist after renaming'); +assert.equal(fs.existsSync(file2), true, + 'Destination file not exist after renaming'); fs.renameSync(file2, file1); + +// Cleanup after test +if (process.platform === 'tizenrt') { + fs.unlinkSync(file1); +} diff --git a/test/run_pass/test_fs_stream_pipe.js b/test/run_pass/test_fs_stream_pipe.js new file mode 100644 index 0000000000..9a5890b644 --- /dev/null +++ b/test/run_pass/test_fs_stream_pipe.js @@ -0,0 +1,83 @@ +/* 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 fs = require('fs'); +var assert = require('assert'); + +if (fs.createReadStream === undefined || fs.createWriteStream === undefined) { + process.exit(0); +} + +var inputFileName = process.cwd() + '/resources/tobeornottobe.txt'; +var outputFileName = process.cwd() + '/tmp/test_fs4.txt'; + +var buff1 = new Buffer(2048); +var buff2 = new Buffer(2048); + +// Get the correct content of the input for later checking. +fs.open(inputFileName, 'r', 0666, function(err, fd) { + if (err) { + throw err; + } + + fs.read(fd, buff1, 0, buff1.length, 0, function(err, bytesRead, buffer) { + if (err) { + throw err; + } + + fs.close(fd, onclose); + }); +}); + +function onclose(err) { + if (err) { + throw err; + } + + var readableFileStream = fs.createReadStream(inputFileName); + var writableFileStream = fs.createWriteStream(outputFileName); + + writableFileStream.on('ready', function() { + readableFileStream.pipe(writableFileStream); + }); + + writableFileStream.on('close', check_output); +} + +function check_output() { + // Read the output for checking. + fs.open(outputFileName, 'r', function(err, fd) { + if (err) { + throw err; + } + + fs.read(fd, buff2, 0, buff2.length, 0, function(err, bytesRead, buffer) { + if (err) { + throw err; + } + + fs.close(fd, function(err) { + if (err) { + throw err; + } + }) + }); + }); +} + +process.on('exit', function() { + assert.equal(buff1.toString(), buff2.toString(), + 'File contents do not match'); +}); diff --git a/test/run_pass/test_fs_write.js b/test/run_pass/test_fs_write.js index 823bfa48e6..c2b562d860 100644 --- a/test/run_pass/test_fs_write.js +++ b/test/run_pass/test_fs_write.js @@ -16,9 +16,14 @@ var fs = require('fs'); var assert = require('assert'); -var dstFilePath = process.cwd() + "/tmp/test_fs3.txt"; -var buff1 = new Buffer("IoT"); -var buff2 = new Buffer(".js"); +var dstFilePath = process.cwd() + '/tmp/test_fs3.txt'; + +if (process.platform === 'tizenrt') { + dstFilePath = '/mnt/test_fs3.txt'; +} + +var buff1 = new Buffer('IoT'); +var buff2 = new Buffer('.js'); fs.open(dstFilePath, 'w+', function(err, fd) { if (err) { diff --git a/test/run_pass/test_fs_write_stream.js b/test/run_pass/test_fs_write_stream.js new file mode 100644 index 0000000000..398f1ae456 --- /dev/null +++ b/test/run_pass/test_fs_write_stream.js @@ -0,0 +1,55 @@ +/* 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 fs = require('fs'); +var assert = require('assert'); + +if (fs.createReadStream === undefined || fs.createWriteStream === undefined) { + process.exit(0); +} + +var dir = (process.platform === 'tizenrt') ? '/mnt/' : process.cwd() + '/tmp/'; +var outputFile = dir + 'test_fs5.txt'; +var testData = 'WriteStream test'; + +var writableFileStream = fs.createWriteStream(outputFile); + +writableFileStream.on('ready', function() { + writableFileStream.write(testData); +}); + +var buff = new Buffer(64); +writableFileStream.on('close', function() { + // Check output correctness + fs.open(outputFile, 'r', 0666, function(err, fd) { + if (err) { + throw err; + } + + fs.read(fd, buff, 0, buff.length, 0, function(err, bytesRead, buffer) { + if (err) { + throw err; + } + + assert.equal(buff.toString(), testData, 'Incorrect data in output file'); + + fs.close(fd, function(err) { + if (err) { + throw err; + } + }); + }); + }) +}); diff --git a/test/run_pass/test_fs_writefile.js b/test/run_pass/test_fs_writefile.js index c2c4be2fd3..86a8989b6b 100644 --- a/test/run_pass/test_fs_writefile.js +++ b/test/run_pass/test_fs_writefile.js @@ -25,6 +25,10 @@ var buff1 = new Buffer('test string1'); var str = 'test string2'; var num = 1; +if (process.platform === 'tizenrt') { + file = '/mnt/test'; +} + fs.writeFile(file, buff1, function (err) { assert.equal(err, null); fs.readFile(file, function (err, buff2) { diff --git a/test/run_pass/test_fs_writefile_sync.js b/test/run_pass/test_fs_writefile_sync.js index 0df492e98d..28e57655b5 100644 --- a/test/run_pass/test_fs_writefile_sync.js +++ b/test/run_pass/test_fs_writefile_sync.js @@ -1,4 +1,3 @@ - /* Copyright 2016-present Samsung Electronics Co., Ltd. and other contributors * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,6 +26,10 @@ var buff2 = null; var str = 'test string2'; var num = 1; +if (process.platform === 'tizenrt') { + file = '/mnt/test'; +} + fs.writeFileSync(file, buff1); buff2 = fs.readFileSync(file); assert.equal(buff2.equals(buff1), true); diff --git a/test/run_pass/test_fs_writefile_unlink.js b/test/run_pass/test_fs_writefile_unlink.js index 4c49701517..8ffda316bb 100644 --- a/test/run_pass/test_fs_writefile_unlink.js +++ b/test/run_pass/test_fs_writefile_unlink.js @@ -20,8 +20,12 @@ var fs = require('fs'); var assert = require('assert'); -var file1 = process.cwd() + "/resources/tobeornottobe.txt"; -var file2 = process.cwd() + "/resources/tobeornottobe_async.txt"; +var file1 = process.cwd() + '/resources/tobeornottobe.txt'; +var file2 = process.cwd() + '/resources/tobeornottobe_async.txt'; + +if (process.platform === 'tizenrt') { + file2 = '/mnt/tobeornottobe_sync.txt'; +} fs.readFile(file1, function(err, buf1) { assert.equal(err, null); diff --git a/test/run_pass/test_fs_writefile_unlink_sync.js b/test/run_pass/test_fs_writefile_unlink_sync.js index 926ed4cb57..fe3b329e06 100644 --- a/test/run_pass/test_fs_writefile_unlink_sync.js +++ b/test/run_pass/test_fs_writefile_unlink_sync.js @@ -16,8 +16,12 @@ var fs = require('fs'); var assert = require('assert'); -var file1 = process.cwd() + "/resources/tobeornottobe.txt"; -var file2 = process.cwd() + "/resources/tobeornottobe_sync.txt"; +var file1 = process.cwd() + '/resources/tobeornottobe.txt'; +var file2 = process.cwd() + '/resources/tobeornottobe_sync.txt'; + +if (process.platform === 'tizenrt') { + file2 = '/mnt/tobeornottobe_sync.txt'; +} /* make a new file2 from file1 */ var buf1 = fs.readFileSync(file1); diff --git a/test/run_pass/test_gpio_api.js b/test/run_pass/test_gpio_api.js new file mode 100644 index 0000000000..0b5ba1242b --- /dev/null +++ b/test/run_pass/test_gpio_api.js @@ -0,0 +1,317 @@ +/* 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 assert = require('assert'); +var gpio = require('gpio'); + +// ------ Test API existance +assert.assert(gpio.DIRECTION, + 'gpio module does not provide \'DIRECTION\' property'); +assert.notEqual(gpio.DIRECTION.IN, undefined); +assert.notEqual(gpio.DIRECTION.OUT, undefined); + +assert.assert(gpio.EDGE, + 'gpio module does not provide \'EDGE\' property'); +assert.notEqual(gpio.EDGE.NONE, undefined); +assert.notEqual(gpio.EDGE.RISING, undefined); +assert.notEqual(gpio.EDGE.FALLING, undefined); +assert.notEqual(gpio.EDGE.BOTH, undefined); + +assert.assert(gpio.MODE, + 'gpio module does not provide \'MODE\' property'); +assert.notEqual(gpio.MODE.NONE, undefined); +if (process.platform === 'nuttx') { + assert.notEqual(gpio.MODE.PULLUP, undefined); + assert.notEqual(gpio.MODE.PULLDOWN, undefined); + assert.notEqual(gpio.MODE.FLOAT, undefined); + assert.notEqual(gpio.MODE.PUSHPULL, undefined); + assert.notEqual(gpio.MODE.OPENDRAIN, undefined); +} + +assert.equal(typeof gpio.open, 'function', + 'gpio does not provide \'open\' function'); +assert.equal(typeof gpio.openSync, 'function', + 'gpio does not provide \'openSync\' function'); + + +function check_gpiopin(gpiopin) { + assert.equal(typeof pin.setDirectionSync, 'function', + '\'gpiopin\' does not provide \'setDirectionSync\' function'); + assert.equal(typeof pin.write, 'function', + '\'gpiopin\' does not provide \'write\' function'); + assert.equal(typeof pin.writeSync, 'function', + '\'gpiopin\' does not provide \'writeSync\' function'); + assert.equal(typeof pin.read, 'function', + '\'gpiopin\' does not provide \'read\' function'); + assert.equal(typeof pin.readSync, 'function', + '\'gpiopin\' does not provide \'readSync\' function'); + assert.equal(typeof pin.close, 'function', + '\'gpiopin\' does not provide \'close\' function'); + assert.equal(typeof pin.closeSync, 'function', + '\'gpiopin\' does not provide \'closeSync\' function'); +} + +// ------ Test synchronous GPIO pin opening +assert.throws( + function() { + gpio.openSync({pin: 0, direction: 123}); + }, + TypeError +); + +assert.throws( + function() { + gpio.openSync({pin: 0, direction: {}}); + }, + TypeError +); + +assert.throws( + function() { + gpio.openSync({pin: 0, direction: 'out'}); + }, + TypeError +); + +assert.throws( + function() { + gpio.openSync({pin: 0, edge: 123}); + }, + TypeError +); + +assert.throws( + function() { + gpio.openSync({pin: 0, edge: {}}); + }, + TypeError +); + +assert.throws( + function() { + gpio.openSync({pin: 0, edge: 'rising'}); + }, + TypeError +); + +assert.throws( + function() { + gpio.openSync({pin: '12'}); + }, + TypeError +); + +assert.throws( + function() { + gpio.openSync({pin: {}}); + }, + TypeError +); + +assert.throws( + function() { + gpio.openSync({pin: -12}); + }, + TypeError +); + +var pin = gpio.openSync({pin: 0, direction: gpio.DIRECTION.OUT}); +check_gpiopin(pin); +pin.closeSync(); + +assert.throws( // close twice + function() { + pin.closeSync(); + }, + Error +); + +pin = gpio.openSync({pin: 0, direction: gpio.DIRECTION.IN}); +check_gpiopin(pin); +pin.closeSync(); + +pin = gpio.openSync({pin: 0}); +check_gpiopin(pin); + +assert.doesNotThrow(function() { + pin.setDirectionSync(gpio.DIRECTION.OUT) +}); + +assert.throws( + function() { + pin.setDirectionSync(123); + }, + TypeError +); + +assert.throws( + function() { + pin.setDirectionSync('out'); + }, + Error +); + +assert.throws( + function() { + pin.setDirectionSync({}); + }, + Error +); + +assert.doesNotThrow( + function() { + pin.writeSync(true); + pin.writeSync(false); + pin.writeSync(0); + pin.writeSync(1); + pin.writeSync(123); + pin.writeSync(-123); + } +); + +assert.doesNotThrow( + function() { + pin.write(true, function(err) { + assert.assert(err === null, 'gpio.write failed: ' + err); + write_cb1 = true; + }); + pin.write(false, function(err) { + assert.assert(err === null, 'gpio.write failed: ' + err); + write_cb2 = true; + }); + pin.write(0, function(err) { + assert.assert(err === null, 'gpio.write failed: ' + err); + write_cb3 = true; + }); + pin.write(1, function(err) { + assert.assert(err === null, 'gpio.write failed: ' + err); + write_cb4 = true; + }); + pin.write(123, function(err) { + assert.assert(err === null, 'gpio.write failed: ' + err); + write_cb5 = true; + }); + pin.write(-123, function(err) { + assert.assert(err === null, 'gpio.write failed: ' + err); + write_cb6 = true; + }); + } +); + +assert.throws( + function() { + pin.writeSync('true'); + }, + Error +); + +assert.throws( + function() { + pin.writeSync({}); + }, + Error +); + +assert.throws( + function() { + gpio.write({}); + }, + Error +); + +assert.throws( + function() { + gpio.write('true'); + }, + Error +); + +pin.write('true', function(err) { + assert.assert(err, 'gpio.write did not fail as expected'); +}); + +pin.write({}, function(err) { + assert.assert(err, 'gpio.write did not fail as expected'); +}); + +// ------ Test asynchronous GPIO pin opening + +var async_pin1 = gpio.open( + { + pin: 20, + direction: gpio.DIRECTION.OUT + }, + function(err, async_pin2) { + open_cb1 = true; + assert.assert(err === null, 'gpio.open failed: ' + err); + assert.assert(async_pin1); + assert.assert(async_pin2); + assert.assert(async_pin1 === async_pin2, + 'return value and callback parameters are not equal'); + check_gpiopin(async_pin2); + async_pin2.close(function(err) { + close_cb1 = true; + assert.assert(err === null, 'gpio.close failed: ' + err); + }); + } +); + +gpio.open( + { + pin: 21, + direction: gpio.DIRECTION.IN + }, + function(err, async_pin) { + open_cb2 = true; + assert.assert(err === null, 'gpio.open failed: ' + err); + check_gpiopin(async_pin); + async_pin.close(function(err) { + close_cb2 = true; + assert.assert(err === null, 'gpio.close failed: ' + err); + }); + } +); + +gpio.open( + { pin: 22 }, + function(err, async_pin) { + open_cb3 = true; + assert.assert(err === null, 'gpio.open failed: ' + err); + check_gpiopin(async_pin); + async_pin.close(function(err) { + close_cb3 = true; + assert.assert(err === null, 'gpio.close failed: ' + err); + }); + } +); + +process.on('exit', function(code) { + if (code === 0) { + assert.assert(open_cb1, 'callback of \'gpio.open\' was not called'); + assert.assert(close_cb1, 'callback of \'gpio.close\' was not called'); + assert.assert(open_cb2, 'callback of \'gpio.open\' was not called'); + assert.assert(close_cb2, 'callback of \'gpio.close\' was not called'); + assert.assert(open_cb3, 'callback of \'gpio.open\' was not called'); + assert.assert(close_cb3, 'callback of \'gpio.close\' was not called'); + + assert.assert(write_cb1, 'callback of \'gpio.write\' was not called'); + assert.assert(write_cb2, 'callback of \'gpio.write\' was not called'); + assert.assert(write_cb3, 'callback of \'gpio.write\' was not called'); + assert.assert(write_cb4, 'callback of \'gpio.write\' was not called'); + assert.assert(write_cb5, 'callback of \'gpio.write\' was not called'); + assert.assert(write_cb6, 'callback of \'gpio.write\' was not called'); + } + pin.closeSync(); +}); diff --git a/test/run_pass/test_gpio_direction.js b/test/run_pass/test_gpio_direction.js new file mode 100644 index 0000000000..52c4688bd0 --- /dev/null +++ b/test/run_pass/test_gpio_direction.js @@ -0,0 +1,41 @@ +/* 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 gpio = require('gpio'); +var pin = require('tools/systemio_common').pin; + +var gpioPin = gpio.openSync({ + pin: pin.led, + direction: gpio.DIRECTION.OUT, +}); + +console.log('GPIO input test. Press the button.'); +gpioPin.setDirectionSync(gpio.DIRECTION.IN); +var loop = setInterval(function() { + var value = gpioPin.readSync(); + console.log('GpioPin value:', value); +}, 500); + +setTimeout(function() { + clearInterval(loop); + + console.log('GPIO output test. Led is on for 5000ms.'); + gpioPin.setDirectionSync(gpio.DIRECTION.OUT); + gpioPin.writeSync(1); + setTimeout(function() { + gpioPin.writeSync(0); + }, 5000); +}, 5000); + diff --git a/test/run_pass/test_gpio_event.js b/test/run_pass/test_gpio_event.js index 7a4cb39c79..2aa55848b1 100644 --- a/test/run_pass/test_gpio_event.js +++ b/test/run_pass/test_gpio_event.js @@ -13,8 +13,7 @@ * limitations under the License. */ -var Gpio = require('gpio'); -var gpio = new Gpio(); +var gpio = require('gpio'); var testGpioInfo = [ { @@ -38,7 +37,7 @@ testGpioInfo.forEach(function(info) { direction: gpio.DIRECTION.IN }, function() { switchGpio.on('change', function() { - console.log('pin:', info.pin, ', current value:', this.readSync()); + console.log('pin:', info.pin, ', current value:', switchGpio.readSync()); }); }); }); diff --git a/test/run_pass/test_gpio_input.js b/test/run_pass/test_gpio_input.js index 220526ec97..c586fc6a96 100644 --- a/test/run_pass/test_gpio_input.js +++ b/test/run_pass/test_gpio_input.js @@ -15,11 +15,11 @@ var assert = require('assert'); -var Gpio = require('gpio'); -var gpio = new Gpio(); +var gpio = require('gpio'); +var pin = require('tools/systemio_common').pin; +var checkError = require('tools/systemio_common').checkError; var ledGpio = null, switchGpio = null; -var ledPin, switchPin, ledMode; var SWITCH_ON = false, LED_ON = true, @@ -27,33 +27,16 @@ var SWITCH_ON = false, var loopCnt = 0; -if (process.platform === 'linux') { - ledPin = 20; - switchPin = 13; - ledMode = gpio.MODE.NONE; -} else if (process.platform === 'nuttx') { - var pin = require('stm32f4dis').pin; - ledPin = pin.PA10; - switchPin = pin.PA15; - ledMode = gpio.MODE.PUSHPULL; -} else if(process.platform === 'tizenrt') { - ledPin = 41; - switchPin = 39; - ledMode = gpio.MODE.NONE; -} else { - assert.fail(); -} - ledGpio = gpio.open({ - pin: ledPin, + pin: pin.led, direction: gpio.DIRECTION.OUT, - mode: ledMode -}, function() { - this.writeSync(LED_OFF); +}, function(err) { + checkError(err); + ledGpio.writeSync(LED_OFF); }); -switchGpio = gpio.open({ - pin: switchPin, +switchGpio = gpio.openSync({ + pin: pin.switch, direction: gpio.DIRECTION.IN }); diff --git a/test/run_pass/test_gpio_output.js b/test/run_pass/test_gpio_output.js index e9b972e9c5..d9a73003d8 100644 --- a/test/run_pass/test_gpio_output.js +++ b/test/run_pass/test_gpio_output.js @@ -15,38 +15,27 @@ var assert = require('assert'); -var Gpio = require('gpio'); -var gpio = new Gpio(); +var gpio = require('gpio'); +var pin = require('tools/systemio_common').pin; +var checkError = require('tools/systemio_common').checkError; var LED_ON = true, LED_OFF = false; -var pin, mode; var gpio20; -if (process.platform === 'linux') { - pin = 20; - mode = gpio.MODE.NONE; -} else if (process.platform === 'nuttx') { - pin = require('stm32f4dis').pin.PA10; - mode = gpio.MODE.PUSHPULL; -} else if(process.platform === 'tizenrt') { - pin = 41; - mode = gpio.MODE.NONE; -} else { - assert.fail(); -} - test1(); gpio20 = gpio.open({ - pin: pin, + pin: pin.led, direction: gpio.DIRECTION.OUT, - mode: mode }, test2); function test1() { + // Check gpio.DIRECTION assert.notEqual(gpio.DIRECTION.IN, undefined); assert.notEqual(gpio.DIRECTION.OUT, undefined); + + // Check gpio.MODE assert.notEqual(gpio.MODE.NONE, undefined); if (process.platform === 'nuttx') { assert.notEqual(gpio.MODE.PULLUP, undefined); @@ -55,6 +44,12 @@ function test1() { assert.notEqual(gpio.MODE.PUSHPULL, undefined); assert.notEqual(gpio.MODE.OPENDRAIN, undefined); } + + // Check gpio.EDGE + assert.notEqual(gpio.EDGE.NONE, undefined); + assert.notEqual(gpio.EDGE.RISING, undefined); + assert.notEqual(gpio.EDGE.FALLING, undefined); + assert.notEqual(gpio.EDGE.BOTH, undefined); } // turn on LED for 3000ms @@ -62,11 +57,11 @@ function test2(err) { assert.equal(err, null); gpio20.write(LED_ON, function(writeErr) { - assert.equal(writeErr, null); + checkError(writeErr); console.log('gpio write'); gpio20.read(function(readErr, value) { - assert.equal(readErr, null); + checkError(readErr); console.log('gpio read:', value); assert.equal(LED_ON, value); @@ -75,8 +70,10 @@ function test2(err) { var value = gpio20.readSync(); console.log('gpio read:', value); assert.equal(LED_OFF, value); - gpio20.close(); - console.log('finish test'); + gpio20.close(function(closeErr) { + checkError(closeErr); + console.log('finish test'); + }); }, 3000); }); }); diff --git a/test/run_pass/test_http_signature.js b/test/run_pass/test_http_signature.js new file mode 100644 index 0000000000..3479bcad97 --- /dev/null +++ b/test/run_pass/test_http_signature.js @@ -0,0 +1,54 @@ +/* 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 fs = require('fs'); +var http_sign = require('http_signature'); +var assert = require('assert'); + +var key = fs.readFileSync(process.cwd() + '/resources/http_signature_key.key'); + +// This is an example request of a Samsung C2C demo +var sampleRequest = { "headers": { + "Content-Type":"application/json", + "Accept":"application/json", + "Authorization":"Signature keyId=\"http_signature_key\"," + + "signature=\"mJUG2ceYWCGww2tXrVJywQUqQvaWbkWpAx4xSfqZD9Gr" + + "G12N8pVysa/nl18kEKe2Sbd00c50qyF/xH5hKtxFyyUYBxY5cOrdt+7W" + + "1EmctaGGIDOnZA/qZcXcnTBZsp8k68XI/6HxwIxHVUntAd2vxJvqzibB" + + "TZLHAhTRVCoAqHzjHe0kybv5oebbMASaNEhZTLslQYQUOYqVzE+4Ecen" + + "Vxrlk2wpjjFjnBdxd/Ek34FTOcWMoPKjpj1ja+hfet2Em8YzF+aeHrBR" + + "t7FTt7r/GkYfuwm9M0XYSY1JvnvCKxIU20YXKbZ+KINBaUXDwEKapUvm" + + "bDFuLi3arJcDigWIOA==\",headers=\"(request-target) digest" + + " date\",algorithm=\"rsa-sha256\"", + "Date":"Tue, 28 Aug 2018 15:28:59 UTC", + "Digest":"SHA-256=52eIrPP0TxhlUVwnChuVLj6qFmbl5dYdMIvUr+DlZ0A=", + "X-ST-CORRELATION":"b7891162-2084-da6e-da84-401be50cd534", + "X-B3-TraceId":"fb04fc10f3088f10", + "X-B3-SpanId":"c6245b1a3c934a0d", + "X-B3-ParentSpanId":"989731b1f545e7d1", + "X-B3-Sampled":"1", + "content-length":"344", + "host":"example.host.com", + "user-agent":"AHC/2.1", + "X-Forwarded-Proto":"https", + "X-Forwarded-For":"52.14.6.245" }, + "method": "POST", + "url": "/", + "httpVersion": "1.1", + }; + + +var parsedRequest = http_sign.parseRequest(sampleRequest); +assert.equal(http_sign.verifySignature(parsedRequest, key), true); diff --git a/test/run_pass/test_i2c.js b/test/run_pass/test_i2c.js deleted file mode 100644 index 3752130562..0000000000 --- a/test/run_pass/test_i2c.js +++ /dev/null @@ -1,51 +0,0 @@ -/* Copyright 2016-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. - */ - -/* This test is based on Raspberry Pi with GY-30 Sensor. */ - -var assert = require('assert'); -var I2C = require('i2c'); - -var i2c = new I2C(); -var configuration = {}; - -configuration.address = 0x23; -if (process.platform === 'linux') { - configuration.device = '/dev/i2c-1'; -} else if (process.platform === 'nuttx') { - configuration.device = 1; -} else { - assert.fail(); -} - -var wire = i2c.open(configuration, function(err) { - if (err) { - throw err; - } - - wire.write([0x10], function(err) { - assert.equal(err, null); - console.log('write done'); - - wire.read(2, function(err, res) { - assert.equal(err, null); - assert.equal(res.length, 2, 'I2C read failed.(length is not equal)'); - console.log('read result: '+res[0]+', '+res[1]); - wire.close(); - console.log('test ok'); - }); - }); -}); - diff --git a/test/run_pass/test_i2c_api.js b/test/run_pass/test_i2c_api.js new file mode 100644 index 0000000000..48b6ee875d --- /dev/null +++ b/test/run_pass/test_i2c_api.js @@ -0,0 +1,165 @@ +/* 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 assert = require('assert'); +var i2c = require('i2c'); + +// ------ Test API existance +assert.equal(typeof i2c.open, 'function', + 'i2c does not provide \'open\' function'); +assert.equal(typeof i2c.openSync, 'function', + 'i2c does not provide \'openSync\' function'); + +function check_i2cbus(i2cbus) { + assert.equal(typeof i2cbus.write, 'function', + '\'i2cpin\' does not provide \'write\' function'); + assert.equal(typeof i2cbus.writeSync, 'function', + '\'i2cpin\' does not provide \'writeSync\' function'); + assert.equal(typeof i2cbus.read, 'function', + '\'i2cpin\' does not provide \'read\' function'); + assert.equal(typeof i2cbus.readSync, 'function', + '\'i2cpin\' does not provide \'readSync\' function'); + assert.equal(typeof i2cbus.close, 'function', + '\'i2cpin\' does not provide \'close\' function'); + assert.equal(typeof i2cbus.closeSync, 'function', + '\'i2cpin\' does not provide \'closeSync\' function'); +} + +// ------ Test synchronous I2C Bus opening +assert.throws( + function() { + i2c.openSync({address: '0x0'}); + }, + TypeError +); + +assert.throws( + function() { + i2c.openSync('0x0'); + }, + Error +); + +assert.throws( + function() { + i2c.openSync({}); + }, + TypeError +); + +var bus = i2c.openSync({address: 0x23}); +check_i2cbus(bus); + +assert.doesNotThrow( + function() { + bus.writeSync([0x10, 123, -12]); + read_result = bus.readSync(5); + } +); + +assert.throws( + function() { + bus.writeSync(0x23); + }, + Error +); + +assert.throws( + function() { + bus.writeSync(null); + }, + Error +); + +assert.throws( + function() { + bus.readSync('5'); + }, + Error +); + +assert.throws( + function() { + bus.readSync(null); + }, + Error +); + +assert.throws( + function() { + bus.readSync([5]); + }, + Error +); + +assert.throws( + function() { + bus.readSync({}); + }, + Error +); + +assert.assert(Array.isArray(read_result)); +assert.strictEqual(read_result.length, 5); + +bus.closeSync(); + +// ------ Test asynchronous I2C Bus opening +i2c.open({address: 0x0}, function(open_err, async_bus) { + assert.equal(open_err, null); + open_cb1 = true; + + assert.throws( + function() { + async_bus.read(null); + }, + Error + ); + + assert.throws( + function() { + async_bus.write(null); + }, + Error + ); + + async_bus.write([0x10, 123, -12], function(write_err) { + assert.equal(write_err, null); + write_cb1 = true; + + async_bus.read(5, function(read_err, res) { + assert.equal(read_err, null); + read_cb1 = true; + assert.assert(Array.isArray(res)); + assert.strictEqual(res.length, 5); + + async_bus.close(function(close_err) { + assert.equal(close_err, null); + close_cb1 = true; + }); + }); + }); +}); + +process.on('exit', function(code) { + if (code === 0) { + assert.assert(open_cb1, 'callback of \'i2c.open\' was not called'); + assert.assert(close_cb1, 'callback of \'i2c.close\' was not called'); + + assert.assert(read_cb1, 'callback of \'i2cbus.read\' was not called'); + assert.assert(write_cb1, 'callback of \'i2cbus.write\' was not called'); + } +}); + diff --git a/test/run_pass/test_i2c_gy30.js b/test/run_pass/test_i2c_gy30.js new file mode 100644 index 0000000000..f942b1668b --- /dev/null +++ b/test/run_pass/test_i2c_gy30.js @@ -0,0 +1,83 @@ +/* Copyright 2016-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. + */ + + +/* This should be tested with GY-30 Sensor. + * + * The following is pin information. + * Linux(Raspberry PI2): BCM2(SDA), BCM3(SCL) + * NuttX(STM32F4-Discovery): PB7(SDA), PB8(SCL) + * TizenRT(Artik053): CON703(10)(SDA), CON703(8)(SCL) - XI2C1 + * +*/ + +var assert = require('assert'); +var pin = require('tools/systemio_common').pin; +var checkError = require('tools/systemio_common').checkError; +var i2c = require('i2c'); + +var configuration = { + address: 0x23, + device: pin.i2c1, // for Linux + bus: pin.i2c1, // for TizenRT and NuttX +}; + +syncTest(); + +function syncTest() { + console.log('I2C sync function test'); + + var wire = i2c.openSync(configuration); + var loopCnt = 5; + + var loop = setInterval(function() { + wire.writeSync([0x10]); + var res = wire.readSync(2); + console.log('read result', (res[1] + (256 * res[0]))); + + if (--loopCnt <= 0) { + clearInterval(loop); + wire.closeSync(); + asyncTest(); + } + }, 800); +} + +function asyncTest() { + console.log('I2C async function test'); + + i2c.open(configuration, function(err, wire) { + checkError(err); + var loopCnt = 5; + + var loop = setInterval(function() { + wire.write([0x10], function(err) { + checkError(err); + + wire.read(2, function(err, res) { + checkError(err); + assert.equal(res.length, 2, 'I2C read failed.(length is not equal)'); + + console.log('read result: ', (res[1] + (256 * res[0]))); + + if (--loopCnt <= 0) { + clearInterval(loop); + wire.close(); + } + }); + }); + }, 800); + }); +} diff --git a/test/run_pass/test_iotjs_promise.js b/test/run_pass/test_iotjs_promise.js index f2725cd7be..9024d5d720 100644 --- a/test/run_pass/test_iotjs_promise.js +++ b/test/run_pass/test_iotjs_promise.js @@ -16,7 +16,7 @@ var assert = require('assert'); var fulfill_ret; var p = new Promise(function(resolve, reject) { // mimic asynchronous operation via setTimeout - setTimeout(function() { resolve("Resolved") }, 100);; + setTimeout(function() { resolve("Resolved") }, 100); }); p.then(function (msg) { @@ -26,4 +26,4 @@ p.then(function (msg) { }); // If Promise's fulfill worked well, assertion must be valid. -setTimeout(function() { assert.equal(fulfill_ret, "Resolved"); }, 200); +setTimeout(function() { assert.equal(fulfill_ret, "Resolved"); }, 1000); diff --git a/test/run_pass/test_iotjs_promise_chain_calls.js b/test/run_pass/test_iotjs_promise_chain_calls.js new file mode 100644 index 0000000000..96e814b049 --- /dev/null +++ b/test/run_pass/test_iotjs_promise_chain_calls.js @@ -0,0 +1,58 @@ +/* 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 fs = require('fs') +var assert = require('assert'); + +function readfile(fileName) { + return new Promise(function (resolve, reject) { + fs.readFile(fileName, function(error, data) { + if (error) { + reject(new Error('Cannot open file!')); + } else { + resolve(data.toString()); + } + }); + }); +}; + +function loadfi(files, idx) { + var fileName = process.cwd() + + '/resources/promise_chain_calls/' + + files[idx]; + + readfile(fileName). + then(function(value) { + assert.equal(value, 'Content of ' + files[idx] + '\n'); + idx++; + loadfi(files, idx); + }).catch(function (e) { + // Note: assert cannot be used here, because exception cannot be thrown + // from Promise.prototype.catch + if (e.message !== "Cannot open file!") { + console.log('Error message does not match. Expected ' + + '"Cannot open file!", but got "' + + e.message + '".'); + process.emitExit(1); + } else if (idx !== 4) { + console.log('Did not read every file. The expected number of files ' + + 'read is "4", but got "' + idx + '".'); + process.emitExit(1); + } + }); +}; + +var files = ['1.txt', '2.txt', '3.txt', '4.txt']; +loadfi(files, 0); diff --git a/test/run_pass/test_module_cache.js b/test/run_pass/test_module_cache.js index 65f3cc3de3..7f174eef03 100644 --- a/test/run_pass/test_module_cache.js +++ b/test/run_pass/test_module_cache.js @@ -15,8 +15,18 @@ var assert = require('assert'); -var module_cache = require('run_pass/require1/module_cache.js'); -module_cache.i = 100; -module_cache = require('run_pass/require1/module_cache.js'); +var dir = process.cwd() + '/run_pass/require1/'; +var dirDoubleDot = dir + '../require1/'; +var dirDot = dir + './'; -assert.equal(module_cache.i, 100); +var moduleCache = require(dir + 'module_cache.js'); +moduleCache.i = 100; + +moduleCache = require(dir + 'module_cache.js'); +assert.equal(moduleCache.i, 100); + +moduleCache = require(dirDoubleDot + 'module_cache.js'); +assert.equal(moduleCache.i, 100); + +moduleCache = require(dirDot + 'module_cache.js'); +assert.equal(moduleCache.i, 100); diff --git a/samples/net_hello/client.js b/test/run_pass/test_module_json.js similarity index 63% rename from samples/net_hello/client.js rename to test/run_pass/test_module_json.js index 8c0dc1d361..3bbc79cf19 100644 --- a/samples/net_hello/client.js +++ b/test/run_pass/test_module_json.js @@ -13,22 +13,12 @@ * limitations under the License. */ -var net = require('net'); +var assert = require('assert'); +var json = require(process.cwd() + '/resources/test.json'); -var port = 7468; - -var msg = ''; -var socket = new net.Socket(); - -var address = process.argv[2] ? process.argv[2] : "127.0.0.1"; - -socket.connect(port, address); - -socket.on('data', function(data) { - msg += data; -}); - -socket.on('end', function() { - console.log(msg); - socket.end(); -}); +assert.equal(json.name, 'IoT.js'); +assert.equal(json.author, 'Samsung Electronics Co., Ltd.'); +assert.equal(json.license, 'Apache-2.0'); +assert.equal(json.number, 123); +assert.equal(Array.isArray(json.array), true); +assert.equal(json.array.toString(), [1,2,3,4].toString()); diff --git a/test/run_pass/test_module_require.js b/test/run_pass/test_module_require.js index 6f350fe2c8..91c0baebe2 100644 --- a/test/run_pass/test_module_require.js +++ b/test/run_pass/test_module_require.js @@ -32,6 +32,11 @@ assert.equal(pkg2.add(22, 44), 66); assert.equal(pkg2.multi(22, 44), 968); assert.equal(pkg2.add2(22, 44), 66); +var pkg3 = require(dir + "test_index2"); +assert.equal(pkg3.add(22, 44), 66); +assert.equal(pkg3.multi(22, 44), 968); +assert.equal(pkg3.add2(22, 44), 66); + // Load invalid modules. assert.throws(function() { var test3 = require('run_pass/require1/babel-template'); diff --git a/test/run_pass/test_mqtt.js b/test/run_pass/test_mqtt.js new file mode 100644 index 0000000000..eb40b6feb4 --- /dev/null +++ b/test/run_pass/test_mqtt.js @@ -0,0 +1,103 @@ +/* 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 mqtt = require('mqtt'); +var assert = require('assert'); + +var connected = false; +var subscribed = false; + +// The number of the variable is the qos level (0-2) + +var msg0 = 'hello iotjs 1'; +var msg1 = 'hello iotjs 2'; +var msg2 = 'hello iotjs 3'; + +var published0 = false; +var published1 = false; +var published2 = false; + +var received0 = false; +var received1 = false; +var received2 = false; + +var subClientOpts = { + clientId: 'iotjs-mqtt-test-sub', + host: 'test.mosquitto.org', + port: 1883, + keepalive: 30, +}; + +var pubClientOpts = { + clientId: 'iotjs-mqtt-test-pub', + port: 1883, + keepalive: 30 +}; + +var pubClient; + +var subClient = mqtt.connect(subClientOpts, function() { + connected = true; + + subClient.subscribe('iotjs-test-topic', { qos:2 }, function() { + subscribed = true; + + pubClient = mqtt.connect('test.mosquitto.org', pubClientOpts, function() { + pubClient.publish('iotjs-test-topic', msg0, { qos:0 }, function() { + published0 = true; + }); + + pubClient.publish('iotjs-test-topic', msg1, { qos:1 }, function() { + published1 = true; + }); + + pubClient.publish('iotjs-test-topic', msg2, { qos:2 }, function() { + published2 = true; + }); + }); + }); + + subClient.on('message', function(data) { + var str = data.message.toString(); + + if (str == msg0) { + received0 = true; + } + + if (str == msg1) { + received1 = true; + } + + if (str == msg2) { + received2 = true; + } + + if (received0 && received1 && received2) { + subClient.end(); + pubClient.end(); + } + }); +}); + +process.on('exit', function() { + assert.equal(connected, true); + assert.equal(subscribed, true); + assert.equal(published0, true); + assert.equal(published1, true); + assert.equal(published2, true); + assert.equal(received0, true); + assert.equal(received1, true); + assert.equal(received2, true); +}); diff --git a/test/run_pass/test_mqtt_frags.js b/test/run_pass/test_mqtt_frags.js new file mode 100644 index 0000000000..27a119ad10 --- /dev/null +++ b/test/run_pass/test_mqtt_frags.js @@ -0,0 +1,144 @@ +/* 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 stream = require('stream'); +var mqtt = require('mqtt'); +var assert = require('assert'); +var fs = require('fs'); + +var duplex = new stream.Duplex(); + +var connect_state = 0; +var recv_count = 0; +var fragment_index = 0; + +// Message we send is always the same, but it is fragmented in different ways +var fragments = [ + // Basic message: + '3014000d67656e6572616c2f746f70696368656c6c6f', + + // One message in three fragments + '30', + '14', + '000d67656e6572616c2f746f70696368656c6c6f', + + // One message in four fragments + '30', + '14', + '00', + '0d67656e6572616c2f746f70696368656c6c6f', + + // One message in five fragments + '30', + '14', + '00', + '0d67656e6572616c2f746f70696368656c6c', + '6f', + + // Two connected messages + '3014000d67656e6572616c2f746f70696368656c6c6f' + + '3014000d67656e6572616c2f746f70696368656c6c6f', + + // Two messages in three fragments + '3014000d67656e6572616c2f74', + '6f70696368656c6c6f3014000d67656e65', + '72616c2f746f70696368656c6c6f', + + // Two messages in three fragments + '3014000d67656e6572616c2f746f70696368656c6c6f30', + '14', + '000d67656e6572616c2f746f70696368656c6c6f', + + // A 132 byte long message + '30', + '87', + '01', + '000d67656e6572616c2f746f706963', + '68656c6c6f68656c6c6f68656c6c6f68656c6c6f', + '68656c6c6f68656c6c6f68656c6c6f68656c6c6f' + + '68656c6c6f68656c6c6f68656c6c6f68656c6c6f' + + '68656c6c6f68656c6c6f68656c6c6f68656c6c6f', + '68656c6c6f68656c6c6f68656c6c6f68656c6c6f' + + '68656c6c6f68656c6c6f68656c6c6f68656c6c6f' +]; + +function send_fragment() { + duplex.push(new Buffer(fragments[fragment_index], 'hex')); + + if (++fragment_index < fragments.length) { + process.nextTick(send_fragment); + } else { + duplex.end(); + } +} + +duplex._write = function(chunk, callback, onwrite) { + onwrite(); + + switch (connect_state) { + case 0: + assert.equal(chunk.toString('hex'), + '100f00044d5154540402001e0003636c69'); + + process.nextTick(function() { + duplex.push(new Buffer('20020000', 'hex')); + }); + break; + + case 1: + assert.equal(chunk.toString('hex'), + '82120000000d67656e6572616c2f746f70696300'); + + process.nextTick(function() { + duplex.push(new Buffer('9003000002', 'hex')); + process.nextTick(send_fragment); + }); + break; + + default: + throw new RangeError("Unknown connection state") + break; + } + + connect_state++; +}; + +duplex._readyToWrite(); + +var mqtt_client = mqtt.connect({ + clientId: 'cli', + keepalive: 30, + socket: duplex, +}, function() { + /* Just subscribe a random topic. */ + mqtt_client.subscribe('general/topic'); +}); + +mqtt_client.on('message', function(data) { + if (recv_count < 10) { + assert.equal(data.message.toString(), 'hello'); + } else { + var str = ''; + for (var i = 0; i < 24; i++) + str += 'hello'; + assert.equal(data.message.toString(), str); + } + + recv_count++; +}); + +mqtt_client.on('finish', function(data) { + assert.equal(recv_count, 11); +}); diff --git a/test/run_pass/test_net_7.js b/test/run_pass/test_net_7.js index faa4a14a09..2d05009173 100644 --- a/test/run_pass/test_net_7.js +++ b/test/run_pass/test_net_7.js @@ -21,7 +21,20 @@ var timers = require('timers'); var port = 22707; var count = 40; +var connectionCount = 0; + +if (process.platform === 'linux' || process.platform === 'darwin' || + process.platform === 'tizen' || process.platform === 'windows') { + var maxConnection = 40; +} else if (process.platform === 'nuttx' || process.platform === 'tizenrt') { + var maxConnection = 5; +} else { + assert.fail(); +} + var check = []; +var queue = []; +var isClose = false; function serverListen() { var server = net.createServer({ @@ -43,6 +56,7 @@ function serverListen() { if (cnt == count) { server.close(); + isClose = true; } }); }); @@ -50,21 +64,43 @@ function serverListen() { serverListen(); -for (var i = 0; i < count; ++i) { - (function(i) { - var socket = new net.Socket(); - var msg = ""; +function connectServer(i) { + connectionCount++; - socket.connect(port, "localhost"); - socket.on('connect', function() { - socket.end(i.toString()); - }); - socket.on('data', function(data) { - check[data] = true; + var socket = new net.Socket(); + var msg = ""; + + socket.connect(port, "localhost"); + socket.on('connect', function() { + socket.end(i.toString(), function() { + connectionCount--; }); - })(i); + }); + socket.on('data', function(data) { + check[data] = true; + }); } +for (var i = 0; i < count; ++i) { + queue.push(i); +} + +var interval = setInterval(function() { + if (isClose) { + clearInterval(interval); + } + + var queueLength = queue.length; + if (connectionCount !== 0 && queueLength === 0) { + return; + } + + var end = maxConnection < queueLength ? maxConnection : queueLength; + queue.splice(0, end).forEach(function(val) { + connectServer(val); + }); +}, 500); + process.on('exit', function(code) { assert.equal(code, 0); for (var i = 0; i < count; ++i) { diff --git a/test/run_pass/test_net_connect.js b/test/run_pass/test_net_connect.js index d1e46e15a8..e129940ab9 100644 --- a/test/run_pass/test_net_connect.js +++ b/test/run_pass/test_net_connect.js @@ -20,10 +20,7 @@ var port = 5696; var msg = 'Hello IoT.js'; var server = net.createServer({ - allowHalfOpen: true, - }, - function(socket) { - server.close(); + allowHalfOpen: true } ).listen(port); @@ -45,6 +42,7 @@ var socket = net.connect(port, host, function() { socket.on('end', function() { assert.equal(data, msg); + server.close(); }); socket.end(msg); diff --git a/test/run_pass/test_net_headers.js b/test/run_pass/test_net_headers.js index 7a559e6b92..798dc474be 100644 --- a/test/run_pass/test_net_headers.js +++ b/test/run_pass/test_net_headers.js @@ -42,7 +42,7 @@ var server = http.createServer(function (req, res) { // final res.headers = { 'h1' : 'h1', 'h3': 'h3prime' } var responseSize; - if (process.platform === 'linux') { + if (process.platform === 'linux' || process.platform === 'tizen') { // For Desktop and RPI, test with large header. responseSize = 500; } else { @@ -53,6 +53,8 @@ var server = http.createServer(function (req, res) { res.setHeader('h' + (5 + i), 'h' + (5 + i)); } + res.setHeader('content-length', 0); + res.end(function(){ server.close(); }); @@ -79,6 +81,7 @@ var postResponseHandler = function (res) { assert.equal(res.headers['h1'], 'h1'); assert.equal(res.headers['h2'], undefined); assert.equal(res.headers['h3'], 'h3prime'); + assert.equal(res.headers['content-length'], 0); var endHandler = function(){ checkReqFinish = true; diff --git a/test/run_pass/test_net_http_methods.js b/test/run_pass/test_net_http_methods.js new file mode 100644 index 0000000000..57dc81abb6 --- /dev/null +++ b/test/run_pass/test_net_http_methods.js @@ -0,0 +1,33 @@ +/* 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 assert = require('assert'); +var http = require('http'); + +assert(http.METHODS instanceof Array, 'http.METHODS should be an array'); + +for (var idx in http.METHODS) { + assert(typeof(http.METHODS[idx]) === 'string', + 'Elements of the http.METHODS should be strings. ' + + 'Found an invalid element, index: ' + idx); +} + +/* Test if at least the basic HTTP methods should be supported */ +var main_methods = ['GET', 'POST', 'PUT', 'DELETE', 'HEAD']; +for (var idx in main_methods) { + var method_name = main_methods[idx]; + assert.notEqual(http.METHODS.indexOf(method_name), -1, + 'http.METHODS is missing the value: ' + method_name); +} diff --git a/test/run_pass/test_net_http_modified_req_resp.js b/test/run_pass/test_net_http_modified_req_resp.js new file mode 100644 index 0000000000..f7f285fdf6 --- /dev/null +++ b/test/run_pass/test_net_http_modified_req_resp.js @@ -0,0 +1,113 @@ +/* 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 assert = require('assert'); +var http = require('http'); + +var response_message = 'DATA'; +var response_got = 'NOT THIS'; + +/* + * Test if 'subclassing' the IncomingMessage + * and ServerResponse is correctly propagated. + */ +function newIncomingMessage() { + http.IncomingMessage.apply(this, arguments); +}; +newIncomingMessage.prototype = Object.create(http.IncomingMessage.prototype); +newIncomingMessage.prototype.extra_field = 'found'; +newIncomingMessage.prototype.waitForBody = function() { + var chunks = []; + this.on('data', function(chunk) { + chunks.push(chunk); + }); + this.on('end', function() { + this.emit('full_body', Buffer.concat(chunks)); + }); +}; + + +function newServerResponse() { + http.ServerResponse.apply(this, arguments); +}; +newServerResponse.prototype = Object.create(http.ServerResponse.prototype); +newServerResponse.prototype.sendJSON = function (obj) { + var message_body = JSON.stringify(obj); + this.setHeader('Content-Length', message_body.length); + this.setHeader('Content-Type', 'application/json'); + this.writeHead(200); + this.end(message_body); +}; + +var serveropts = { + IncomingMessage: newIncomingMessage, + ServerResponse: newServerResponse, +}; + +var server = http.createServer(serveropts, function (req, res) { + assert.equal(req.method, 'POST', 'Incorrect request method detected'); + assert.equal(req.url, '/put_msg', 'Incorrect request url detected'); + assert.assert(req instanceof http.IncomingMessage, + 'Request is not instance of http.IncomingMessage'); + assert.assert(req instanceof newIncomingMessage, + 'Request is not instance of the new Request object'); + assert.equal(req.extra_field, 'found', + 'No "extra_field" property on the request instance'); + + req.waitForBody(); + req.on('full_body', function(body) { + assert.assert(body instanceof Buffer); + assert.equal(body.toString(), 'DEMO'); + + res.sendJSON({message: response_message}); + }); +}); + +server.listen(3001); + +var demo_msg = 'DEMO'; +var options = { + method : 'POST', + port : 3001, + path : '/put_msg', + headers: { + 'Content-Length': demo_msg.length, + }, +}; +var req = http.request(options, function (response){ + var content_type = + response.headers['Content-Type'] || response.headers['content-type'] + assert.equal(content_type, 'application/json', + 'Incorrect content type returned by the server'); + + var chunks = [] + response.on('data', function(chunk) { + chunks.push(chunk); + }); + response.on('end', function() { + var body = JSON.parse(Buffer.concat(chunks).toString()); + assert.assert('message' in body, 'No "message" key in response JSON'); + response_got = body.message; + + server.close(); + }); +}); + +req.end(demo_msg); + +process.on('exit', function() { + assert.equal(response_got, response_message, + 'Invalid response returned from the demo server'); +}); diff --git a/test/run_pass/test_net_http_modified_request.js b/test/run_pass/test_net_http_modified_request.js new file mode 100644 index 0000000000..6bad6ea0d3 --- /dev/null +++ b/test/run_pass/test_net_http_modified_request.js @@ -0,0 +1,104 @@ +/* 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 assert = require('assert'); +var http = require('http'); + +var response_message = 'DATA'; +var response_got = 'NOT THIS'; + +/* + * Test if 'subclassing' the IncomingMessage + * and ServerResponse is propagated correctly. + */ +function newIncomingMessage() { + http.IncomingMessage.apply(this, arguments); +}; +newIncomingMessage.prototype = Object.create(http.IncomingMessage.prototype); +newIncomingMessage.prototype.extra_field = 'found'; +newIncomingMessage.prototype.waitForBody = function() { + var chunks = []; + this.on('data', function(chunk) { + chunks.push(chunk); + }); + this.on('end', function() { + this.emit('full_body', Buffer.concat(chunks)); + }); +}; + + +var serveropts = { + IncomingMessage: newIncomingMessage, +}; + +var server = http.createServer(serveropts, function (req, res) { + assert.equal(req.method, 'POST', 'Incorrect request method detected'); + assert.equal(req.url, '/put_msg', 'Incorrect request url detected'); + assert.assert(req instanceof http.IncomingMessage, + 'Request is not instance of http.IncomingMessage'); + assert.assert(req instanceof newIncomingMessage, + 'Request is not instance of the new Request object'); + assert.equal(req.extra_field, 'found', + 'No "extra_field" property on the request instance'); + + req.waitForBody(); + req.on('full_body', function(body) { + assert.assert(body instanceof Buffer); + assert.equal(body.toString(), 'DEMO'); + + var message_body = JSON.stringify({message: response_message}); + res.setHeader('Content-Length', message_body.length); + res.setHeader('Content-Type', 'application/json'); + res.writeHead(200); + res.end(message_body); + }); +}); + +server.listen(3001); + +var demo_msg = 'DEMO'; +var options = { + method : 'POST', + port : 3001, + path : '/put_msg', + headers: { + 'Content-Length': demo_msg.length, + }, +}; +var req = http.request(options, function (response){ + var content_type = + response.headers['Content-Type'] || response.headers['content-type'] + assert.equal(content_type, 'application/json', + 'Incorrect content type returned by the server'); + + var chunks = [] + response.on('data', function(chunk) { + chunks.push(chunk); + }); + response.on('end', function() { + var body = JSON.parse(Buffer.concat(chunks).toString()); + assert.assert('message' in body, 'No "message" key in response JSON'); + response_got = body.message; + + server.close(); + }); +}); + +req.end(demo_msg); + +process.on('exit', function() { + assert.equal(response_got, response_message, + 'Invalid response returned from the demo server'); +}); diff --git a/test/run_pass/test_net_http_modified_response.js b/test/run_pass/test_net_http_modified_response.js new file mode 100644 index 0000000000..ec7ca6c6ba --- /dev/null +++ b/test/run_pass/test_net_http_modified_response.js @@ -0,0 +1,94 @@ +/* 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 assert = require('assert'); +var http = require('http'); + +var response_message = 'DATA'; +var response_got = 'NOT THIS'; + +/* + * Test if 'subclassing' the ServerResponse is propagated correctly. + */ +function newServerResponse() { + http.ServerResponse.apply(this, arguments); +}; +newServerResponse.prototype = Object.create(http.ServerResponse.prototype); +newServerResponse.prototype.sendJSON = function (obj) { + var message_body = JSON.stringify(obj); + this.setHeader('Content-Length', message_body.length); + this.setHeader('Content-Type', 'application/json'); + this.writeHead(200); + this.end(message_body); +}; + +var serveropts = { + ServerResponse: newServerResponse, +}; + +var server = http.createServer(serveropts, function (req, res) { + assert.equal(req.method, 'POST', 'Incorrect request method detected'); + assert.equal(req.url, '/put_msg', 'Incorrect request url detected'); + assert.assert(req instanceof http.IncomingMessage, + 'Request is not instance of http.IncomingMessage'); + + var chunks = []; + req.on('data', function(chunk) { + chunks.push(chunk); + }); + req.on('end', function() { + var body = Buffer.concat(chunks); + assert.equal(body.toString(), 'DEMO'); + + res.sendJSON({message: response_message}); + }); +}); + +server.listen(3001); + +var demo_msg = 'DEMO'; +var options = { + method : 'POST', + port : 3001, + path : '/put_msg', + headers: { + 'Content-Length': demo_msg.length, + }, +}; +var req = http.request(options, function (response){ + var content_type = + response.headers['Content-Type'] || response.headers['content-type'] + assert.equal(content_type, 'application/json', + 'Incorrect content type returned by the server'); + + var chunks = [] + response.on('data', function(chunk) { + chunks.push(chunk); + }); + response.on('end', function() { + var body = JSON.parse(Buffer.concat(chunks).toString()); + assert.assert('message' in body, 'No "message" key in response JSON'); + response_got = body.message; + + server.close(); + }); +}); + +req.end(demo_msg); + +process.on('exit', function() { + assert.equal(response_got, response_message, + 'Invalid response returned from the demo server'); +}); diff --git a/test/run_pass/test_net_http_outgoing_buffer.js b/test/run_pass/test_net_http_outgoing_buffer.js new file mode 100644 index 0000000000..c6adb737c9 --- /dev/null +++ b/test/run_pass/test_net_http_outgoing_buffer.js @@ -0,0 +1,60 @@ +/* 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 http = require('http'); +var assert = require('assert'); + +var clientMessage = new Buffer([0xE6, 0x7F, 0x3, 0x6, 0x7]); +var serverMessage = new Buffer([0x3, 0x7F, 0x6, 0x7, 0xE6]); +var serverReceived; +var clientReceived; + +var server = http.createServer(function(req, res) { + var received = []; + req.on('data', function(data) { + received.push(data); + }); + req.on('end', function() { + serverReceived = Buffer.concat(received); + res.end(serverMessage); + }); +}).listen(8383, 5); + +var reqOpts = { + method: 'POST', + port: 8383, + path: '/', + headers: {'Content-Length': clientMessage.length}, +}; + +var clientReq = http.request(reqOpts, function(res) { + var response = []; + + res.on('data', function(data) { + response.push(data); + }); + + res.on('end', function() { + clientReceived = Buffer.concat(response); + server.close(); + }); +}); + +clientReq.end(clientMessage); + +process.on('exit', function() { + assert.equal(serverReceived.compare(clientMessage), 0); + assert.equal(clientReceived.compare(serverMessage), 0); +}); diff --git a/test/run_pass/test_net_http_request_http_version.js b/test/run_pass/test_net_http_request_http_version.js new file mode 100644 index 0000000000..318d32e3b0 --- /dev/null +++ b/test/run_pass/test_net_http_request_http_version.js @@ -0,0 +1,40 @@ +/* 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 assert = require('assert'); +var http = require('http'); + +var server = http.createServer(function(request, response) { + // the http version in IoT.js is hardcoded to 1.1 + assert.equal(request.httpVersion, "1.1", + "incorrect http version returned via the http request object"); + + response.writeHead(200); + response.end(); +}); +server.listen(3008, 5); + +var request = http.request({ + method: 'HEAD', + port: 3008, + path: '/' +}, function(response) { + assert.equal(response.statusCode, 200); + + response.on('end', function() { + server.close(); + }); +}) +request.end(); diff --git a/test/run_pass/test_net_http_request_response.js b/test/run_pass/test_net_http_request_response.js index c94202f63a..e7615b7bf9 100644 --- a/test/run_pass/test_net_http_request_response.js +++ b/test/run_pass/test_net_http_request_response.js @@ -73,12 +73,6 @@ request2.end(message, function() { isRequest2Finished = true; }); -// Call the request2 end again to test the finish state. -request2.end(message, function() { - // This clabback should never be called. - assert.equal(isRequest2Finished, false); -}); - var server3 = http.createServer(function(request, response) { var str = ''; @@ -170,18 +164,26 @@ request5.end(); // Test the IncomingMessage read function. +var server6 = http.createServer(function(request, response) { + request.on('end', function() { + response.end('ok'); + server6.close(); + }); +}).listen(8080, 5); + var readRequest = http.request({ - host: 'localhost', - port: 80, + host: '127.0.0.1', + port: 8080, path: '/', method: 'GET' }); readRequest.end(); + readRequest.on('response', function(incomingMessage) { incomingMessage.on('readable', function() { var inc = incomingMessage.read(); assert.equal(inc instanceof Buffer, true); - assert(inc.toString('utf8').length > 0); + assert.assert(inc.toString('utf8').length > 0); }); }); diff --git a/test/run_pass/test_net_httpserver.js b/test/run_pass/test_net_http_server.js similarity index 98% rename from test/run_pass/test_net_httpserver.js rename to test/run_pass/test_net_http_server.js index 912c9ec0aa..2033f115af 100644 --- a/test/run_pass/test_net_httpserver.js +++ b/test/run_pass/test_net_http_server.js @@ -14,9 +14,8 @@ */ var assert = require('assert'); -var Server = require('http_server').Server; var http = require('http'); - +var Server = http.Server; var responseCheck = ''; var connectionEvent = 0; @@ -78,6 +77,7 @@ var msg = 'http request test msg'; var options = { method : 'POST', port : 3001, + rejectUnauthorized: false, headers : {'Content-Length': msg.length} }; @@ -148,6 +148,7 @@ var finalMsg = 'close server'; var finalOptions = { method : 'POST', port : 3001, + rejectUnauthorized: false, headers : {'Content-Length': finalMsg.length} }; diff --git a/test/run_pass/test_net_httpserver_timeout.js b/test/run_pass/test_net_http_server_timeout.js similarity index 98% rename from test/run_pass/test_net_httpserver_timeout.js rename to test/run_pass/test_net_http_server_timeout.js index 51390663c9..bb44cc4544 100644 --- a/test/run_pass/test_net_httpserver_timeout.js +++ b/test/run_pass/test_net_http_server_timeout.js @@ -47,3 +47,5 @@ process.on('exit', function(code) { assert.equal(timeouted, true); assert.equal(code, 0); }); + +getReq.end(); diff --git a/test/run_pass/test_net_http_status_codes.js b/test/run_pass/test_net_http_status_codes.js index 4f3af50d12..f134e64719 100644 --- a/test/run_pass/test_net_http_status_codes.js +++ b/test/run_pass/test_net_http_status_codes.js @@ -1,4 +1,3 @@ - /* Copyright 2017-present Samsung Electronics Co., Ltd. and other contributors * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,9 +16,14 @@ var assert = require('assert'); var http = require('http'); -var codes = ["100", "150", "199", "200", "204", "304", "404", "510"]; +var codes = ["150", "199", "200", "204", "304", "404", "510"]; +var queue = codes.slice(0); var responses = []; -var completedResponses = 0; +var options = { + method: 'POST', + port: 3008, + headers: {'Content-Length': 3} +}; var server = http.createServer(function (request, response) { var str = ''; @@ -33,57 +37,29 @@ var server = http.createServer(function (request, response) { response.writeHead(parseInt(str)); } - response.write(str); - response.end(function() { - if(str == 'close server') { - server.close(); - } - }); + response.end(); }); -}); +}).listen(3008, 5); -server.listen(3008, 5); +requestOnQueue(queue.shift()); -var options = { - method: 'POST', - port: 3008, - headers: {'Content-Length': 3} -}; +function requestOnQueue(code) { + var request = http.request(options, function(res) { + responses.push(res.statusCode); + if (responses.length == codes.length) { + // Done with downloads. + for (var j = 0; j < codes.length; j++) { + assert(responses.indexOf(parseInt(codes[j])) > -1); + } -for (var i = 0; i < codes.length; i++) { - var request = http.request(options, function(response) { - responses.push(response.statusCode); - completedResponses++; - if (completedResponses == codes.length) { - // Done with downloads. - for (var j = 0; j < codes.length; j++) { - assert(responses.indexOf(parseInt(codes[j])) > -1); + server.close(); + } else { + if(queue.length) { + process.nextTick(function() { + requestOnQueue(queue.shift()); + }); + } } - } - }).end(codes[i]); + }).end(code); } - -var closeMessage = 'close server'; -var closeOptions = { - method : 'POST', - port : 3008, - headers : {'Content-Length': closeMessage.length} -}; -var closeHandler = function(response) { - var str = ''; - - assert.equal(200, response.statusCode); - - response.on('end', function() { - assert.equal(closeMessage, str); - }); - - response.on('data', function(chunk) { - str += chunk; - }); -}; - -closeRequest = http.request(closeOptions, closeHandler); -closeRequest.write(closeMessage); -closeRequest.end(); diff --git a/test/run_pass/test_net_httpclient_error.js b/test/run_pass/test_net_httpclient_error.js index 1f628ad79e..ff4751a0fc 100644 --- a/test/run_pass/test_net_httpclient_error.js +++ b/test/run_pass/test_net_httpclient_error.js @@ -56,9 +56,8 @@ req.on('error', function() { server.close(); }); -req.setTimeout(100, function(){ - req.end(); -}); +req.end(); + process.on('exit', function() { assert.equal(recievedResponse, false); diff --git a/test/run_pass/test_net_httpclient_parse_error.js b/test/run_pass/test_net_httpclient_parse_error.js index ec66d00e08..9d18dfa542 100644 --- a/test/run_pass/test_net_httpclient_parse_error.js +++ b/test/run_pass/test_net_httpclient_parse_error.js @@ -39,7 +39,6 @@ request.on('error', function(err) { request.end(); process.on('exit', function() { - // The first error is a Parse Error. - // The second error is the socket hang up. - assert.equal(errors, 2); + // The error is a Parse Error. + assert.equal(errors, 1); }); diff --git a/test/run_pass/test_net_https_get.js b/test/run_pass/test_net_https_get.js new file mode 100644 index 0000000000..83c09dba41 --- /dev/null +++ b/test/run_pass/test_net_https_get.js @@ -0,0 +1,87 @@ +/* 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 https = require('https'); + + +var isRequest1Finished = false; +// 1. GET req +options = { + method: 'GET', + host: 'httpbin.org', + path: '/user-agent', + rejectUnauthorized: false, + headers: {'user-agent': 'iotjs'} +}; + +var getResponseHandler = function (res) { + var res_body = ''; + + assert.equal(200, res.statusCode); + + var endHandler = function(){ + var response = JSON.parse(res_body); + assert.equal('iotjs', response['user-agent']); + isRequest1Finished = true; + }; + res.on('end', endHandler); + + res.on('data', function(chunk){ + res_body += chunk.toString(); + }); +}; + +https.get(options, getResponseHandler); + +// 2. close server req +var testMsg = 'Hello IoT.js'; +var finalOptions = { + method: 'POST', + host: 'httpbin.org', + path: '/post', + rejectUnauthorized: false, + headers: {'Content-Length': testMsg.length, + 'Content-Type': 'application/json'} +}; +var isRequest2Finished = false; + +var finalResponseHandler = function (res) { + var res_body = ''; + + assert.equal(200, res.statusCode); + + var endHandler = function(){ + var response = JSON.parse(res_body); + assert.equal(testMsg, response['data']); + isRequest2Finished = true; + }; + res.on('end', endHandler); + + res.on('data', function(chunk){ + res_body += chunk.toString(); + }); +}; + +var finalReq = https.request(finalOptions, finalResponseHandler); +finalReq.write(testMsg); +finalReq.end(); + + +process.on('exit', function() { + assert.equal(isRequest1Finished, true); + assert.equal(isRequest2Finished, true); +}); diff --git a/test/run_pass/test_net_https_modified_req_resp.js b/test/run_pass/test_net_https_modified_req_resp.js new file mode 100644 index 0000000000..5d2d3f9665 --- /dev/null +++ b/test/run_pass/test_net_https_modified_req_resp.js @@ -0,0 +1,119 @@ +/* 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 assert = require('assert'); +var fs = require('fs'); +var http = require('http'); +var https = require('https'); + +var response_message = 'DATA'; +var response_got = 'NOT THIS'; + +/* + * Test if 'subclassing' the IncomingMessage + * and ServerResponse is correctly propagated. + */ +function newIncomingMessage() { + http.IncomingMessage.apply(this, arguments); +}; +newIncomingMessage.prototype = Object.create(http.IncomingMessage.prototype); +newIncomingMessage.prototype.extra_field = 'found'; +newIncomingMessage.prototype.waitForBody = function() { + var chunks = []; + this.on('data', function(chunk) { + chunks.push(chunk); + }); + this.on('end', function() { + this.emit('full_body', Buffer.concat(chunks)); + }); +}; + + +function newServerResponse() { + http.ServerResponse.apply(this, arguments); +}; +newServerResponse.prototype = Object.create(http.ServerResponse.prototype); +newServerResponse.prototype.sendJSON = function (obj) { + var message_body = JSON.stringify(obj); + this.setHeader('Content-Length', message_body.length); + this.setHeader('Content-Type', 'application/json'); + this.writeHead(200); + this.end(message_body); +}; + +var serveropts = { + IncomingMessage: newIncomingMessage, + ServerResponse: newServerResponse, + + key: fs.readFileSync(process.cwd() + '/resources/my_key.key'), + cert: fs.readFileSync(process.cwd() + '/resources/my_crt.crt') +}; + +var server = https.createServer(serveropts, function (req, res) { + assert.equal(req.method, 'POST', 'Incorrect request method detected'); + assert.equal(req.url, '/put_msg', 'Incorrect request url detected'); + assert.assert(req instanceof http.IncomingMessage, + 'Request is not instance of http.IncomingMessage'); + assert.assert(req instanceof newIncomingMessage, + 'Request is not instance of the new Request object'); + assert.equal(req.extra_field, 'found', + 'No "extra_field" property on the request instance'); + + req.waitForBody(); + req.on('full_body', function(body) { + assert.assert(body instanceof Buffer); + assert.equal(body.toString(), 'DEMO'); + + res.sendJSON({message: response_message}); + }); +}); + +server.listen(3001); + +var demo_msg = 'DEMO'; +var options = { + method : 'POST', + port : 3001, + path : '/put_msg', + headers: { + 'Content-Length': demo_msg.length, + }, + rejectUnauthorized: false +}; +var req = https.request(options, function (response){ + var content_type = + response.headers['Content-Type'] || response.headers['content-type'] + assert.equal(content_type, 'application/json', + 'Incorrect content type returned by the server'); + + var chunks = [] + response.on('data', function(chunk) { + chunks.push(chunk); + }); + response.on('end', function() { + var body = JSON.parse(Buffer.concat(chunks).toString()); + assert.assert('message' in body, 'No "message" key in response JSON'); + response_got = body.message; + + server.close(); + }); +}); + +req.end(demo_msg); + +process.on('exit', function() { + assert.equal(response_got, response_message, + 'Invalid response returned from the demo server'); +}); diff --git a/test/run_pass/test_net_https_post_status_codes.js b/test/run_pass/test_net_https_post_status_codes.js new file mode 100644 index 0000000000..a7213d09a9 --- /dev/null +++ b/test/run_pass/test_net_https_post_status_codes.js @@ -0,0 +1,57 @@ +/* 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 https = require('https'); + +var isRequest1Finished = false; +// 1. POST req +var data = JSON.stringify({}); + +var options = { + method: 'POST', + hostname: 'httpbin.org', + path: '/post', + rejectUnauthorized: false, + headers: { + 'content-type': 'application/json', + 'content-length': data.length, + } +}; + +var getResponseHandler = function(res) { + var res_body = ''; + assert.equal(200, res.statusCode); + + var endHandler = function() { + var response = JSON.parse(res_body); + assert.assert(response['data'], 'Recieved incorrect response from server'); + isRequest1Finished = true; + }; + res.on('end', endHandler); + + res.on('data', function(chunk) { + res_body += chunk.toString(); + }); +}; + +var req = https.request(options, getResponseHandler); +req.write(data); +req.end(); + +process.on('exit', function() { + assert.equal(isRequest1Finished, true); +}); diff --git a/test/run_pass/test_net_https_request_response.js b/test/run_pass/test_net_https_request_response.js new file mode 100644 index 0000000000..e9bdd4d030 --- /dev/null +++ b/test/run_pass/test_net_https_request_response.js @@ -0,0 +1,115 @@ +/* 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 http = require('http'); +var https = require('https'); +var net = require('net'); + +// Messages for further requests. +var message = 'Hello IoT.js'; + +// Options for further requests. +var options = { + method: 'POST', + host: 'httpbin.org', + path: '/post', + rejectUnauthorized: false, + headers: {'Content-Length': message.length, + 'Content-Type': 'application/json'} +}; + +// Simple request with valid utf-8 message. +var isRequest1Finished = false; +var request1 = https.request(options, function(response) { + var str = ''; + + response.on('data', function(chunk) { + str += chunk.toString(); + }); + + response.on('end', function() { + var response = JSON.parse(str); + assert.equal(message, response['data']); + isRequest1Finished = true; + }); +}); +request1.end(message); + + +// Simple request with multiple end callback. +var isRequest2Finished = false; +var request2 = https.request(options, function(response) { + var str = ''; + + response.on('data', function(chunk) { + str += chunk.toString(); + }); + + response.on('end', function() { + var response = JSON.parse(str); + assert.equal(message, response['data']); + }); +}); + +request2.end(message, function() { + isRequest2Finished = true; +}); + + +// Simple request with buffer chunk as message parameter. +var isRequest3Finished = false; +var request3 = https.request(options, function(response) { + var str = ''; + + response.on('data', function(chunk) { + str += chunk; + }); + + response.on('end', function() { + var response = JSON.parse(str); + assert.equal(message, response['data']); + isRequest3Finished = true; + }); +}); +request3.end(new Buffer(message)); + + +// Test the IncomingMessage read function. +var isRequest4Finished = false; +var readRequest = https.request({ + method: 'GET', + host: 'httpbin.org', + rejectUnauthorized: false, + path: '/get' +}); + +readRequest.on('response', function(incomingMessage) { + incomingMessage.on('readable', function() { + var inc = incomingMessage.read(); + assert.equal(inc instanceof Buffer, true); + assert(inc.toString('utf8').length > 0); + isRequest4Finished = true; + }); +}); +readRequest.end(); + + +process.on('exit', function() { + assert.equal(isRequest1Finished, true); + assert.equal(isRequest2Finished, true); + assert.equal(isRequest3Finished, true); + assert.equal(isRequest4Finished, true); +}); diff --git a/test/run_pass/test_net_https_server.js b/test/run_pass/test_net_https_server.js new file mode 100644 index 0000000000..d1120088e9 --- /dev/null +++ b/test/run_pass/test_net_https_server.js @@ -0,0 +1,54 @@ +/* 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 assert = require('assert'); +var https = require('https'); +var fs = require('fs'); + +var server_options = { + key: fs.readFileSync(process.cwd() + '/resources/my_key.key').toString(), + cert: fs.readFileSync(process.cwd() + '/resources/my_crt.crt').toString() +}; + +var server = https.createServer(server_options, function(req, res) { + res.writeHead(200); + res.end('hello world\n'); +}).listen(8000); + + +var client_options = { + host: 'localhost', + port: 8000, + rejectUnauthorized: false +} + +var responseHandler = function (res) { + var res_body = ''; + + assert.equal(200, res.statusCode); + + var endHandler = function(){ + assert.equal(res_body, 'hello world\n'); + }; + res.on('end', endHandler); + + res.on('data', function(chunk){ + res_body += chunk.toString(); + }); + + server.close(); +} + +https.get(client_options, responseHandler); diff --git a/samples/http_hello/client_get.js b/test/run_pass/test_net_https_timeout.js similarity index 61% rename from samples/http_hello/client_get.js rename to test/run_pass/test_net_https_timeout.js index 7bcefceb47..a722040ad5 100644 --- a/samples/http_hello/client_get.js +++ b/test/run_pass/test_net_https_timeout.js @@ -13,27 +13,28 @@ * limitations under the License. */ -var http = require('http'); -var options = { - hostname: '127.0.0.1', - port: 8080, - path: '/' + + +var assert = require('assert'); +var https = require('https'); + +options = { + method: 'GET', + host: 'httpbin.org', + rejectUnauthorized: false, + path: '/delay/10' }; -http.request(options, function (res) { - receive(res, function (data) { - console.log(data); - }); -}).end(); +var getReq = https.get(options); -function receive(incoming, callback) { - var data = ''; +getReq.on('error', function(){}); - incoming.on('data', function (chunk) { - data += chunk; - }); +var timeouted = false; +getReq.setTimeout(5000, function() { + timeouted = true; + getReq.abort(); +}); - incoming.on('end', function () { - callback ? callback(data) : ''; - }); -} +process.on('exit', function(code) { + assert.equal(timeouted, true); +}); diff --git a/test/run_pass/test_process_chdir.js b/test/run_pass/test_process_chdir.js index bd8b6f0441..ca534b4de2 100644 --- a/test/run_pass/test_process_chdir.js +++ b/test/run_pass/test_process_chdir.js @@ -22,6 +22,12 @@ try { console.log('invalid path'); } -assert.equal(process.cwd(), '/'); +var newPath = process.cwd(); +if (process.platform === "windows") { + /* check if the path is in format: :\ */ + assert.equal(newPath.substr(1), ':\\'); +} else { + assert.equal(newPath, '/'); +} process.chdir(currentPath); diff --git a/test/run_pass/test_pwm.js b/test/run_pass/test_pwm.js deleted file mode 100644 index fba7ae009a..0000000000 --- a/test/run_pass/test_pwm.js +++ /dev/null @@ -1,129 +0,0 @@ -/* Copyright 2016-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 Pwm = require('pwm'); - -var pwm = new Pwm(); - -var configuration = { - period: 0.001 // 1kHz -}; - -if (process.platform === 'linux') { - configuration.pin = 0; -} else if (process.platform === 'nuttx') { - configuration.pin = require('stm32f4dis').pin.PWM1.CH1_1; -} else if (process.platform === 'tizenrt') { - configuration.pin = 0; -} else { - assert.fail(); -} - -var periodOptions = { - dutyCycle: 0.5, - // The platform PWM is tested on (artik10/tizen 3.0) has an upper limit - // of 75.2 Hz of PWM0 frequency. - //values: [0.2, 0.4, 0.6, 0.8, 1] - values: [ 0.5 ] -}; - -var dutyOptions = { - period: 0.5, - values: [ 0, 0.1, 0.5, 0.9, 1 ] -}; - -var testCb = function (err) { - if (err) { - assert.fail(); - } -}; - -var pwm0; -testPeriods(); - -function testPeriods() { - pwm0 = pwm.open(configuration, function (err) { - console.log('PWM initialized'); - - if (err) { - console.log('Have an error: ' + err.message); - assert.fail(); - } - - pwm0.setEnable(1, function(err) { - testCb(err); - - var options = periodOptions; - console.log('PWM: period test start '); - var idx = 0; - var period = options.values[idx++]; - console.log("Period(%d)", period); - pwm0.setFrequencySync(1.0 / period); - pwm0.setDutyCycleSync(options.dutyCycle); - - var loop = setInterval(function () { - if (idx == options.values.length) { - clearInterval(loop); - console.log('PWM period test complete'); - pwm0.setPeriodSync(options.values[0]); - pwm0.setEnableSync(0); - pwm0.closeSync(); - testDutyCycles(); - } else { - period = options.values[idx++]; - console.log("Period(%d)", period); - pwm0.setPeriod(period, testCb); - } - }, 1000); - }); - }); -} - -function testDutyCycles() { - var options = dutyOptions; - - console.log('PWM: duty cycle test start'); - pwm0 = pwm.open(configuration, function (err) { - console.log('PWM initialized'); - - if (err) { - console.log('Have an error: ' + err.message); - assert.fail(); - } - - pwm0.setPeriod(options.period, function(err) { - testCb(err); - - pwm0.setEnableSync(1, testCb); - pwm0.setFrequency(1.0 / options.period, function(err) { - testCb(err); - var idx = 0; - var loop = setInterval(function () { - console.log('Duty cycle %d', options.values[idx]); - pwm0.setDutyCycle(options.values[idx], testCb); - - if (++idx == options.values.length) { - clearInterval(loop); - pwm0.setEnableSync(0); - pwm0.close(testCb.bind(err)); - console.log('PWM duty cycle test complete'); - } - }, 1000); - }); - }); - }); -} diff --git a/test/run_pass/test_pwm_api.js b/test/run_pass/test_pwm_api.js new file mode 100644 index 0000000000..241467bd17 --- /dev/null +++ b/test/run_pass/test_pwm_api.js @@ -0,0 +1,274 @@ +/* Copyright 2019-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 pwm = require('pwm'); + +// ------ Test API existance +assert.equal(typeof pwm.open, 'function', + 'pwm does not provide \'open\' function'); +assert.equal(typeof pwm.openSync, 'function', + 'pwm does not provide \'openSync\' function'); + +function check_pwmpin(pwmpin) { + assert.equal(typeof pwmpin.setPeriod, 'function', + '\'pwmpin\' does not provide \'setPeriod\' function'); + assert.equal(typeof pwmpin.setPeriodSync, 'function', + '\'pwmpin\' does not provide \'setPeriodSync\' function'); + assert.equal(typeof pwmpin.setFrequency, 'function', + '\'pwmpin\' does not provide \'setFrequency\' function'); + assert.equal(typeof pwmpin.setFrequencySync, 'function', + '\'pwmpin\' does not provide \'setFrequencySync\' function'); + assert.equal(typeof pwmpin.setDutyCycle, 'function', + '\'pwmpin\' does not provide \'setDutyCycle\' function'); + assert.equal(typeof pwmpin.setDutyCycleSync, 'function', + '\'pwmpin\' does not provide \'setDutyCycleSync\' function'); + assert.equal(typeof pwmpin.setEnable, 'function', + '\'pwmpin\' does not provide \'setEnable\' function'); + assert.equal(typeof pwmpin.setEnableSync, 'function', + '\'pwmpin\' does not provide \'setEnableSync\' function'); + assert.equal(typeof pwmpin.close, 'function', + '\'pwmpin\' does not provide \'close\' function'); + assert.equal(typeof pwmpin.closeSync, 'function', + '\'pwmpin\' does not provide \'closeSync\' function'); +} + +// ------ Test synchronous PWM Pin opening +assert.throws( + function() { + pwm.openSync({period: 0.1, + dutyCycle: 0.5}); + }, + TypeError +); + +assert.throws( + function() { + pwm.openSync({pin: 0, + period: 0.1, + dutyCycle: 1.1}); + }, + RangeError +); + +assert.throws( + function() { + pwm.openSync({pin: 0, + period: -0.1, + dutyCycle: 0.5}); + }, + RangeError +); + +assert.throws( + function() { + pwm.openSync({}); + }, + TypeError +); + +var config = { + pin: 0, + period: 0.1, + dutyCycle: 0.5 +} + +var pwmpin = pwm.openSync(config); +check_pwmpin(pwmpin); + +assert.doesNotThrow( + function() { + pwmpin.setPeriodSync(1); + } +); + +assert.throws( + function() { + pwmpin.setPeriodSync(); + }, + Error +); + +assert.throws( + function() { + pwmpin.setPeriodSync(null); + }, + Error +); + +assert.doesNotThrow( + function() { + pwmpin.setFrequencySync(1); + } +); + +assert.throws( + function() { + pwmpin.setFrequencySync(); + }, + Error +); + +assert.throws( + function() { + pwmpin.setFrequencySync(null); + }, + Error +); + +assert.doesNotThrow( + function() { + pwmpin.setDutyCycleSync(1); + } +); + +assert.throws( + function() { + pwmpin.setDutyCycleSync(); + }, + Error +); + +assert.throws( + function() { + pwmpin.setDutyCycleSync(null); + }, + Error +); + +assert.doesNotThrow( + function() { + pwmpin.setEnableSync(false); + } +); + +assert.throws( + function() { + pwmpin.setEnableSync(); + }, + Error +); + +assert.throws( + function() { + pwmpin.setEnableSync(null); + }, + Error +); + +pwmpin.closeSync(); + +// ------ Test asynchronous PWM Pin opening +pwm.open(config, function(open_err, async_pwmpin) { + assert.equal(open_err, null); + open_cb1 = true; + + assert.throws( + function() { + pwmpin.setPeriod(); + }, + Error + ); + + assert.throws( + function() { + pwmpin.setPeriod(null); + }, + Error + ); + + assert.throws( + function() { + pwmpin.setFrequency(); + }, + Error + ); + + assert.throws( + function() { + pwmpin.setFrequency(null); + }, + Error + ); + + assert.throws( + function() { + pwmpin.setDutyCycle(); + }, + Error + ); + + assert.throws( + function() { + pwmpin.setDutyCycle(null); + }, + Error + ); + + assert.throws( + function() { + pwmpin.setEnableSync(); + }, + Error + ); + + assert.throws( + function() { + pwmpin.setEnableSync(null); + }, + Error + ); + + async_pwmpin.setPeriod(1, function(period_err) { + assert.equal(period_err, null); + period_cb1 = true; + + async_pwmpin.setFrequency(1, function(frequency_err, res) { + assert.equal(frequency_err, null); + frequency_cb1 = true; + + async_pwmpin.setDutyCycle(1, function(dutycycle_err, res) { + assert.equal(dutycycle_err, null); + dutycycle_cb1 = true; + + async_pwmpin.setEnable(true, function(enable_err, res) { + assert.equal(enable_err, null); + enable_cb1 = true; + + async_pwmpin.close(function(close_err) { + assert.equal(close_err, null); + close_cb1 = true; + }); + }); + }); + }); + }); +}); + +process.on('exit', function(code) { + if (code === 0) { + assert.assert(open_cb1, 'callback of \'pwm.open\' was not called'); + assert.assert(close_cb1, 'callback of \'pwm.close\' was not called'); + + assert.assert(period_cb1, + 'callback of \'pwmpin.setPeriod\' was not called'); + assert.assert(frequency_cb1, + 'callback of \'pwmpin.setFrequency\' was not called'); + assert.assert(dutycycle_cb1, + 'callback of \'pwmpin.setDutyCycle\' was not called'); + assert.assert(enable_cb1, + 'callback of \'pwmpin.setEnable\' was not called'); + } +}); diff --git a/test/run_pass/test_pwm_async.js b/test/run_pass/test_pwm_async.js new file mode 100644 index 0000000000..44bbe7f12c --- /dev/null +++ b/test/run_pass/test_pwm_async.js @@ -0,0 +1,95 @@ +/* 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 pwm = require('pwm'); +var pin = require('tools/systemio_common').pin; +var checkError = require('tools/systemio_common').checkError; + +var dutyCycles = [0.25, 0.5, 0.75], + frequencies = [1, 10, 30], + periodInit = false, + dutyCycleInit = false; + +var configuration = { + period: 0.001, // 1kHz + dutyCycle: dutyCycles[0], + pin: pin.pwm1 +}; + +function initPwm(pwm) { + pwm.setPeriod(0.001, function(err) { + checkError(err); + periodInit = true; + }); + pwm.setDutyCycle(0.5, function(err) { + checkError(err); + dutyCycleInit = true; + }); +} + +var pwm0 = null; +pwm0 = pwm.open(configuration, function (err) { + console.log('PWM initialized'); + checkError(err); + + pwm0.setEnable(true, checkError); + dutyCycleTest(); +}); + +function dutyCycleTest() { + var loopCnt = 0; + + var loop = setInterval(function() { + if (pwm0 === null) { + return; + } + + if (loopCnt >= dutyCycles.length) { + clearInterval(loop); + initPwm(pwm0); + console.log('PWM duty-cycle test complete'); + frequencyTest(); + return; + } + console.log("dutycycle(%d)", dutyCycles[loopCnt]); + pwm0.setDutyCycle(dutyCycles[loopCnt++], checkError); + }, 1000); +} + +function frequencyTest() { + var loopCnt = 0; + + var loop = setInterval(function() { + if (!dutyCycleInit || !periodInit) { + return; + } + + if (loopCnt >= frequencies.length) { + clearInterval(loop); + pwm0.setEnable(false, function(err) { + checkError(err); + pwm0.close(function(err) { + checkError(err); + console.log('PWM frequency test complete'); + }); + }); + return; + } + + console.log("frequency(%d)", frequencies[loopCnt]); + pwm0.setFrequency(frequencies[loopCnt++], checkError); + }, 2000); +} diff --git a/test/run_pass/test_pwm_sync.js b/test/run_pass/test_pwm_sync.js new file mode 100644 index 0000000000..f4b293aaf2 --- /dev/null +++ b/test/run_pass/test_pwm_sync.js @@ -0,0 +1,76 @@ +/* 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 pwm = require('pwm'); +var pin = require('tools/systemio_common').pin; +var checkError = require('tools/systemio_common').checkError; + +var dutyCycles = [0.25, 0.5, 0.75], + frequencies = [1, 10, 30]; + +var configuration = { + period: 0.001, // 1kHz + dutyCycle: dutyCycles[0], + pin: pin.pwm1 +}; + +function initPwm(pwm) { + pwm.setPeriodSync(0.001); + pwm.setDutyCycleSync(0.5); +} + +var pwm0 = null; +pwm0 = pwm.openSync(configuration); +console.log('PWM initialized'); + +pwm0.setEnableSync(true); +dutyCycleTest(); + +function dutyCycleTest() { + var loopCnt = 0; + + var loop = setInterval(function() { + if (pwm0 === null) { + return; + } + + if (loopCnt >= dutyCycles.length) { + clearInterval(loop); + initPwm(pwm0); + console.log('PWM duty-cycle test complete'); + frequencyTest(); + return; + } + console.log("dutycycle(%d)", dutyCycles[loopCnt]); + pwm0.setDutyCycleSync(dutyCycles[loopCnt++]); + }, 1000); +} + +function frequencyTest() { + var loopCnt = 0; + + var loop = setInterval(function() { + if (loopCnt >= frequencies.length) { + clearInterval(loop); + pwm0.setEnableSync(false); + pwm0.closeSync(); + console.log('PWM frequency test complete'); + return; + } + console.log("frequency(%d)", frequencies[loopCnt]); + pwm0.setFrequencySync(frequencies[loopCnt++]); + }, 2000); +} diff --git a/test/run_pass/test_spi.js b/test/run_pass/test_spi.js new file mode 100644 index 0000000000..4fd01d0813 --- /dev/null +++ b/test/run_pass/test_spi.js @@ -0,0 +1,71 @@ +/* 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 spi = require('spi'); +var pin = require('tools/systemio_common').pin; + +var configuration = { + device: pin.spi1, // for Linux + bus: pin.spi1, // for Tizen, TizenRT and Nuttx +}; + + +// ------ Test API existance +assert.assert(spi.MODE, + 'spi module does not provide \'MODE\' property'); +assert.assert(spi.CHIPSELECT, + 'spi module does not provide \'CHIPSELECT\' property'); +assert.assert(spi.BITORDER, + 'spi module does not provide \'BITORDER\' property'); +assert.equal(typeof spi.open, 'function', + 'spi does not provide \'open\' function'); +assert.equal(typeof spi.openSync, 'function', + 'spi does not provide \'openSync\' function'); + + +// ------ Test basic API functions +var data = 'Hello IoTjs'; +var tx = new Buffer(data); + +var spi1 = spi.open(configuration, function(err) { + assert.assert(err === null, 'spi.open failed: ' + err); + + assert.equal(typeof spi1.transfer, 'function', + 'spibus does not provide \'transfer\' function'); + assert.equal(typeof spi1.transferSync, 'function', + 'spibus does not provide \'transferSync\' function'); + assert.equal(typeof spi1.close, 'function', + 'spibus does not provide \'close\' function'); + assert.equal(typeof spi1.closeSync, 'function', + 'spibus does not provide \'closeSync\' function'); + + spi1.transfer(tx, function(err, rx) { + assert.assert(err === null, 'spibus.transfer failed: ' + err); + + spi1.close(function(err) { + assert.assert(err === null, 'spibus.close failed: ' + err); + testSync(); + }); + }); +}); + +function testSync() { + var spi2 = spi.open(configuration, function(err) { + assert.assert(err === null, 'spi.open for sync test failed: ' + err); + var rx = spi2.transferSync(tx); + spi2.closeSync(); + }); +} diff --git a/test/run_pass/test_spi_buffer.js b/test/run_pass/test_spi_buffer_async.js similarity index 53% rename from test/run_pass/test_spi_buffer.js rename to test/run_pass/test_spi_buffer_async.js index 2e43f5a601..04ad0a9691 100644 --- a/test/run_pass/test_spi_buffer.js +++ b/test/run_pass/test_spi_buffer_async.js @@ -14,37 +14,35 @@ */ var assert = require('assert'); -var Spi = require('spi'); +var spi = require('spi'); +var pin = require('tools/systemio_common').pin; +var checkError = require('tools/systemio_common').checkError; -var spi = new Spi(); +var configuration = { + device: pin.spi1, // for Linux + bus: pin.spi1, // for Tizen, TizenRT and Nuttx +}; // Buffer test -var spi1 = spi.open({device: '/dev/spidev0.0'}, function() { +var spi1 = spi.open(configuration, function(err) { + checkError(err); var data = 'Hello IoTjs'; var tx = new Buffer(data); - var rx = new Buffer(11); - this.transferSync(tx, rx); - var value = ''; - for (var i = 0; i < 11; i++) { - value += String.fromCharCode(rx[i]); - } - console.log(value); - assert.equal(value, data); + spi1.transfer(tx, function(err, rx) { + checkError(err); + var len = data.length; + assert.equal(rx.length, len); - setTimeout(function() { - spi1.transfer(tx, rx, function(err) { - assert.equal(err, null); - assert.equal(rx.length, 11); + var value = ''; + for (var i = 0; i < len; i++) { + value += String.fromCharCode(rx[i]); + } + console.log(value); + assert.equal(value, data); - var value = ''; - for (var i = 0; i < 11; i++) { - value += String.fromCharCode(rx[i]); - } - console.log(value); - assert.equal(value, data); - - spi1.close(); + spi1.close(function(err) { + checkError(err); }); - }, 500); + }); }); diff --git a/test/run_pass/test_spi_buffer_sync.js b/test/run_pass/test_spi_buffer_sync.js new file mode 100644 index 0000000000..2539e4b40a --- /dev/null +++ b/test/run_pass/test_spi_buffer_sync.js @@ -0,0 +1,40 @@ +/* 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 assert = require('assert'); +var spi = require('spi'); +var pin = require('tools/systemio_common').pin; + +var configuration = { + device: pin.spi1, // for Linux + bus: pin.spi1, // for Tizen, TizenRT and Nuttx +}; + +// Buffer test +var spi1 = spi.openSync(configuration); +var data = 'Hello IoTjs'; +var tx = new Buffer(data); + +var rx = spi1.transferSync(tx); +var len = data.length; +assert.equal(rx.length, len); +var value = ''; +for (var i = 0; i < len; i++) { + value += String.fromCharCode(rx[i]); +} +console.log(value); +assert.equal(value, data); + +spi1.closeSync(); diff --git a/test/run_pass/test_spi_mcp3008.js b/test/run_pass/test_spi_mcp3008.js index 327cf993c7..c1b88c3a5e 100644 --- a/test/run_pass/test_spi_mcp3008.js +++ b/test/run_pass/test_spi_mcp3008.js @@ -14,26 +14,30 @@ */ var assert = require('assert'); -var Spi = require('spi'); +var spi = require('spi'); +var pin = require('tools/systemio_common').pin; +var checkError = require('tools/systemio_common').checkError; -var spi = new Spi(); +var configuration = { + device: pin.spi1, // for Linux + bus: pin.spi1, // for Tizen, TizenRT and Nuttx +}; // mcp3008 test var channel = 0; -var spi0 = spi.open({ - device: '/dev/spidev0.0' -}, function() { +var spi0 = spi.open(configuration, function(err) { + checkError(err); + var mode = (8 + channel) << 4; var tx = [1, mode, 0]; - var rx = [0, 0, 0]; - spi0.transferSync(tx, rx); + var rx = spi0.transferSync(tx); console.log(((rx[1] & 0x03) << 8) + rx[2]); var loopCnt = 10; var loop = setInterval(function() { - spi0.transfer(tx, rx, function(err) { - assert.equal(err, null); + spi0.transfer(tx, function(err, rx) { + checkError(err); assert.equal(rx.length, 3); var value = ((rx[1] & 0x03) << 8) + rx[2]; diff --git a/test/run_pass/test_stream_pipe.js b/test/run_pass/test_stream_pipe.js new file mode 100644 index 0000000000..bc98059762 --- /dev/null +++ b/test/run_pass/test_stream_pipe.js @@ -0,0 +1,206 @@ +/* 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 assert = require('assert'); +var net = require('net'); +var stream = require('stream'); +var Duplex = stream.Duplex; +var Readable = stream.Readable; +var Writable = stream.Writable; + +var readable = new Readable(); + +var msg = []; +var resp = []; + +// Test case 1: basic data correctness. +var dest1 = new Writable(); + +msg.push('Hello'); + +dest1._write = function(chunk, callback, onwrite) { + resp.push(chunk.toString()); +} + +dest1._readyToWrite(); + +readable.pipe(dest1); +readable.push(msg[0]); +readable.unpipe(dest1); + +// Test case 2: serial piping. +var dest2 = new Duplex(); +var dest3 = new Duplex(); +var dest4 = new Duplex(); + +msg.push('data'); + +dest2._write = function(chunk, callback, onwrite) { + this.push(chunk); + resp.push(chunk.toString()); +} + +dest3._write = function(chunk, callback, onwrite) { + this.push(chunk); + resp.push(chunk.toString()); +} + +dest4._write = function(chunk, callback, onwrite) { + resp.push(chunk.toString()); +} + +dest2._readyToWrite(); +dest3._readyToWrite(); +dest4._readyToWrite(); + +readable.pipe(dest2).pipe(dest3).pipe(dest4); +readable.push(msg[1]); +readable.unpipe(dest2); +dest2.unpipe(dest3); +dest3.unpipe(dest4); + +// Test case 3: unpipe test. +var dest5 = new Writable(); + +var dest5_write_called = false; +dest5._write = function(chunk, callback, onwrite) { + dest5_write_called = true; +} + +dest5._readyToWrite(); + +readable.pipe(dest5); +readable.unpipe(dest5); +readable.push('foo'); + +// Test case 4: pushing data to the readable stream +// before piping it. +var readable2 = new Readable(); +var dest6 = new Writable(); +msg.push('data before pipe'); + +dest6._write = function(chunk, callback, onwrite) { + resp.push(chunk.toString()); +} + +dest6._readyToWrite(); + +readable2.push(msg[2]); +readable2.pipe(dest6); +readable2.unpipe(dest6); + +// Test case 5: piping multiple destinations to a single Readable +var readable3 = new Readable(); +msg.push('Multiple pipe test'); + +var dest7 = new Writable(); +var dest8 = new Duplex(); + +dest7._write = function(chunk, callback, onwrite) { + resp.push(chunk.toString()); +} + +dest8._write = function(chunk, callback, onwrite) { + resp.push(chunk.toString()); +} + +dest7._readyToWrite(); +dest8._readyToWrite(); + +readable.pipe(dest7); +readable.pipe(dest8); +readable.push(msg[3]); +readable.unpipe(dest7); +readable.unpipe(dest8); + +// Test case 6: piping with net.Socket source +msg.push('Hello from the server'); + +var server = net.createServer({}, function(socket) { + socket.write(msg[4]); +}); +server.listen(8080); + +var dest9 = new Duplex(); + +dest9._write = function(chunk, callback, onwrite) { + resp.push(chunk.toString()); + this.emit('_write_done'); +} + +// This is needed to make sure that the order of the results in the resp +// array is correct. +dest9.on('_write_done', testCase7); + +dest9._readyToWrite(); + +var socket = new net.Socket(); +socket.pipe(dest9); + +socket.on('data', function(data) { + socket.end(); +}); + +socket.on('end', function() { + socket.unpipe(dest9); + server.close(); +}); + +socket.connect({'port': 8080}); + +// Test case 7: piping with net.Socket destination +function testCase7() { + msg.push('Hello from the socket'); + + var server2 = net.createServer({}, function(socket) { + socket.on('data', function(data) { + resp.push(data.toString()); + socket.end(); + }); + }); + server2.listen(8081); + + var socket2 = new net.Socket(); + + socket2.on('data', function(data) { + socket2.write(data); + }); + + socket2.on('end', function() { + server2.close(); + }); + + var readable4 = new Readable(); + readable4.pipe(socket2); + socket2.connect({'port': 8081}); + readable4.push(msg[5]); + readable4.unpipe(socket2); + socket2.end(); +} + +// checking the results +process.on('exit', function() { + assert.equal(msg[0], resp[0], 'Basic data correctness test failed'); + assert.equal(msg[1], resp[1], 'Serial pipe test failed'); + assert.equal(msg[1], resp[2], 'Serial pipe test failed'); + assert.equal(msg[1], resp[3], 'Serial pipe test failed'); + assert.equal(dest5_write_called, false, 'Unpipe test failed'); + assert.equal(msg[2], resp[4], 'Incorrect data when pushing to the ' + + 'readable stream before piping'); + assert.equal(msg[3], resp[5], 'Multiple piping test failed'); + assert.equal(msg[3], resp[6], 'Multiple piping test failed'); + assert.equal(msg[4], resp[7], 'net.Socket source piping test failed'); + assert.equal(msg[5], resp[8], 'net.Socket destination piping test failed'); +}); diff --git a/test/run_pass/test_tizen_app_control.js b/test/run_pass/test_tizen_app_control.js new file mode 100644 index 0000000000..c72c0c6591 --- /dev/null +++ b/test/run_pass/test_tizen_app_control.js @@ -0,0 +1,42 @@ +/* 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 tizen = require('tizen'); + +// Need to set target APP_ID e.g) app.control.receiver +var app_id = ''; +var data = { + str: 'iotjs' +}; + +// test: tizen.on +tizen.on('appControl', function(msg) { + console.log('appControl', msg); + + var extra_data = msg.extra_data; + if(extra_data && extra_data.key === 'iotjs' ) { + + //test: tizen.launchAppControl + try { + var res = tizen.launchAppControl({ + app_id: app_id, + extra_data: data, + }); + console.log('Result', res); + } catch(e) { + console.log(e); + } + } +}); diff --git a/test/run_pass/test_tls_1.js b/test/run_pass/test_tls_1.js new file mode 100644 index 0000000000..6e2063d807 --- /dev/null +++ b/test/run_pass/test_tls_1.js @@ -0,0 +1,64 @@ +/* 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 assert = require('assert'); +var fs = require('fs'); +var tls = require('tls'); + +var tlsClientError_caught = false; +var socket_handshake_error_caught = false; + +var port = 8080; + +var server_options = { + rejectUnauthorized: false, + isServer: true +} + +var server = tls.createServer(server_options, function(socket) { +}).listen(port, function() {}); + +server.on('tlsClientError', function(error) { + tlsClientError_caught = error instanceof Error; + server.close(); +}); + +var socket_options = { + host: '127.0.0.1', + port: port, + rejectUnauthorized: false +} + +var socket = tls.connect(socket_options, function() {}); + +socket.on('error', function(error) { + socket_handshake_error_caught = error instanceof Error; +}); + +function createServerFailed(server_options) { + assert.throws(function() { + return tls.createServer(server_options); + }); +} + +createServerFailed({key: 0}); +createServerFailed({cert: null}); +createServerFailed({key: false, cert: 7}); +createServerFailed({ca: true}); + +process.on('exit', function() { + assert.equal(tlsClientError_caught, true); + assert.equal(socket_handshake_error_caught, true); +}); diff --git a/test/run_pass/test_tls_2.js b/test/run_pass/test_tls_2.js new file mode 100644 index 0000000000..d4dcf4ed51 --- /dev/null +++ b/test/run_pass/test_tls_2.js @@ -0,0 +1,92 @@ +/* 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 assert = require('assert'); +var fs = require('fs'); +var tls = require('tls'); + +var expected_client_msg = 'Client hello'; +var expected_server_msg = 'Server hello'; +var client_message = ''; +var server_message = ''; +var server_closed = false; +var server_handshake_done = false; +var error_caught = false; +var handshake_done = false; + +var port = 8080; + +var server_options = { + key: fs.readFileSync(process.cwd() + '/resources/my_key.key').toString(), + cert: fs.readFileSync(process.cwd() + '/resources/my_crt.crt'), + rejectUnauthorized: false, + isServer: true +}; + +var server = tls.createServer(server_options, function(socket1) { + socket1.write('Server hello'); + + socket1.on('data', function(data) { + client_message += data.toString(); + }); + +}).listen(port, function() {}); + +server.on('secureConnection', function() { + server_handshake_done = true; +}); + +server.on('close', function() { + server_closed = true; +}); + +var socket_options = { + host: '127.0.0.1', + port: port, + rejectUnauthorized: false +} + +var socket1 = tls.connect(socket_options, function() {}); + +socket1.on('secureConnect', function() { + handshake_done = true; +}); + +socket1.on('end', function() { + server.close(); +}); + +socket1.on('data', function(data) { + server_message += data.toString(); + socket1.write('Client hello'); + socket1.end(); +}); + +var socket2 = tls.connect({host: '127.123.123.123', port: 444}, function() { + socket2.end(); +}); + +socket2.on('error', function(err) { + error_caught = true; +}); + +process.on('exit', function() { + assert.equal(error_caught, true); + assert.equal(handshake_done, true); + assert.equal(server_handshake_done, true); + assert.equal(client_message === expected_client_msg, true); + assert.equal(server_message === expected_server_msg, true); + assert.equal(server_closed, true); +}); diff --git a/test/run_pass/test_tls_3.js b/test/run_pass/test_tls_3.js new file mode 100644 index 0000000000..f96768a052 --- /dev/null +++ b/test/run_pass/test_tls_3.js @@ -0,0 +1,100 @@ +/* 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 assert = require('assert'); +var fs = require('fs'); +var tls = require('tls'); + +var expected_client_msg = 'Client hello'; +var expected_server_msg = 'Server hello'; +var client_message = ''; +var server_message = ''; +var server_closed = false; +var server_handshake_done = false; +var handshake_done = false; + +var port = 8080; + +var server_options = { + key: fs.readFileSync(process.cwd() + '/resources/my_key.key').toString(), + cert: fs.readFileSync(process.cwd() + '/resources/my_crt.crt'), + rejectUnauthorized: false, + isServer: true +}; + +var server = tls.createServer(server_options, function(socket) { + socket.write('Server hello'); + + socket.on('data', function(data) { + client_message = data.toString(); + }); + +}).listen(port, function() {}); + +server.on('secureConnection', function() { + server_handshake_done = true; +}); + +server.on('close', function() { + server_closed = true; +}); + +var socket1 = tls.connect(port); + +socket1.on('secureConnect', function() { + handshake_done = true; +}); + +socket1.on('data', function(data) { + server_message = data.toString(); + socket1.write('Client hello'); + socket1.end(); +}); + +var socket2 = tls.connect(port, 'localhost'); + +socket2.on('secureConnect', function() { + handshake_done = true; +}); + +socket2.on('data', function(data) { + server_message = data.toString(); + socket2.write('Client hello'); + socket2.end(); +}); + +var socket3 = tls.connect(port, function() {}); + +socket3.on('secureConnect', function() { + handshake_done = true; +}); + +socket3.on('data', function(data) { + server_message = data.toString(); + socket3.write('Client hello'); + socket3.end(); +}); + +socket3.on('end', function() { + server.close(); +}); + +process.on('exit', function() { + assert.equal(handshake_done, true); + assert.equal(server_handshake_done, true); + assert.equal(client_message === expected_client_msg, true); + assert.equal(server_message === expected_server_msg, true); + assert.equal(server_closed, true); +}); diff --git a/test/run_pass/test_tls_4.js b/test/run_pass/test_tls_4.js new file mode 100644 index 0000000000..18e7df3411 --- /dev/null +++ b/test/run_pass/test_tls_4.js @@ -0,0 +1,104 @@ +/* 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 assert = require('assert'); +var fs = require('fs'); +var tls = require('tls'); + +var expected_client_msg = 'Client hello'; +var expected_server_msg = 'Server hello'; +var client_message = ''; +var server_message = ''; +var server_closed = false; +var server_handshake_done = false; +var handshake_done = false; + +var port = 8080; + +var server_options = { + key: fs.readFileSync(process.cwd() + '/resources/my_key.key').toString(), + cert: fs.readFileSync(process.cwd() + '/resources/my_crt.crt'), + rejectUnauthorized: false, + isServer: true +}; + +var server = tls.createServer(server_options, function(socket) { + socket.write('Server hello'); + + socket.on('data', function(data) { + client_message = data.toString(); + }); + +}).listen(port, function() { }); + +server.on('secureConnection', function() { + server_handshake_done = true; +}); + +server.on('close', function() { + server_closed = true; +}); + +var socket_options = { + rejectUnauthorized: false, +} + +var socket1 = tls.connect(port, 'localhost', socket_options); + +socket1.on('secureConnect', function() { + handshake_done = true; +}); + +socket1.on('data', function(data) { + server_message = data.toString(); + socket1.write('Client hello'); + socket1.end(); +}); + +var socket2 = tls.connect(port, 'localhost', socket_options, function() {}); + +socket1.on('secureConnect', function() { + handshake_done = true; +}); + +socket2.on('data', function(data) { + server_message = data.toString(); + socket2.write('Client hello'); + socket2.end(); +}); + +var socket3 = tls.connect(port, 'localhost', function() {}); + +socket3.on('secureConnect', function(){ + handshake_done = true; +}); + +socket3.on('data', function(data) { + server_message = data.toString(); + socket3.write('Client hello'); + socket3.end(); +}); + +socket3.on('end', function() { + server.close(); +}); + +process.on('exit', function() { + assert.equal(handshake_done, true); + assert.equal(server_handshake_done, true); + assert.equal(client_message === expected_client_msg, true); + assert.equal(server_message === expected_server_msg, true); + assert.equal(server_closed, true); +}); diff --git a/test/run_pass/test_tls_ca.js b/test/run_pass/test_tls_ca.js new file mode 100644 index 0000000000..337b605c65 --- /dev/null +++ b/test/run_pass/test_tls_ca.js @@ -0,0 +1,114 @@ +/* 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. + */ + +/* + For this test, we created a certificate authority, and signed + a certificate request with it. Here are the steps taken: + + 1) created a secret rsa key for ourselves + + openssl genrsa -out my_key.key 2048 + + Verify (dump): openssl rsa -in my_key.key -noout -text + + 2) created a secret rsa key for our certificate authority (CA) + + openssl genrsa -out my_ca.key 2048 + + Verify (dump): openssl rsa -in my_ca.key -noout -text + + 3) created a certificate signing request (CSR), + which is signed by the CA later + + openssl req -new -key my_key.pem -out my_csr.csr + + Country Name (2 letter code) [AU]:HU + State or Province Name (full name) [Some-State]: + Locality Name (eg, city) []:Szeged + Organization Name (eg, company) [Internet Widgits Pty Ltd]:Trusted + Organizational Unit Name (eg, section) []: + Common Name (e.g. server FQDN or YOUR name) []:localhost + Email Address []:trusted@localhost + + Please enter the following 'extra' attributes + to be sent with your certificate request + A challenge password []:ch+llenGe + An optional company name []: + + Verify (dump): openssl req -in my_csr.csr -noout -text + + 4) created a self-signed certificate for the CA + + openssl req -new -x509 -key my_ca.key -out my_ca.crt + + Country Name (2 letter code) [AU]:HU + State or Province Name (full name) [Some-State]: + Locality Name (eg, city) []:Szeged + Organization Name (eg, company) [Internet Widgits Pty Ltd]:My CA + Organizational Unit Name (eg, section) []: + Common Name (e.g. server FQDN or YOUR name) []:myca.org + Email Address []:myca@myca.org + + Verify (dump): openssl x509 -in my_ca.crt -noout -text + + 5) sign our certificate signing request + + openssl x509 -req -in my_csr.csr -CA my_ca.crt -CAkey my_ca.key \ + -CAcreateserial -out my_crt.crt + + Note: A my_ca.srl file is also created to record the already + issued serial numbers. This file is needed for future + certificate signings. + + Verify (dump): openssl x509 -in my_crt.crt -noout -text +*/ + +var tls = require('tls'); +var assert = require('assert'); +var fs = require('fs'); + +var port = 8080; + +var server_message = ''; + +var options = { + key: fs.readFileSync(process.cwd() + '/resources/my_key.key').toString(), + cert: fs.readFileSync(process.cwd() + '/resources/my_crt.crt') +}; + +var server = tls.createServer(options, function(socket) { + socket.write('Server hello'); +}).listen(port); + +var sockOpts = { + // The my_crt.crt certificate was issued for localhost as server FQDN + // Anything else here (e.g. 127.0.0.1) makes the handshake failed + host: 'localhost', + port: port, + rejectUnauthorized: true, + ca: fs.readFileSync(process.cwd() + '/resources/my_ca.crt') +} + +var socket = tls.connect(sockOpts, function() { + socket.on('data', function(data) { + server_message += data.toString(); + socket.end(); + server.close(); + }); +}); + +process.on('exit', function() { + assert.equal(server_message, 'Server hello'); +}); diff --git a/test/run_pass/test_tls_stream_duplex.js b/test/run_pass/test_tls_stream_duplex.js new file mode 100644 index 0000000000..40b43eeab3 --- /dev/null +++ b/test/run_pass/test_tls_stream_duplex.js @@ -0,0 +1,105 @@ +/* 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 stream = require('stream'); +var tls = require('tls'); +var assert = require('assert'); +var fs = require('fs'); + +var tls1_message = 'Hello, this is tls1'; +var tls1_expected_message = tls1_message; +var tls2_message = 'Hello, this is tls2'; +var tls2_expected_message = tls2_message; +var tls1_received_message = ''; +var tls2_received_message = ''; +var tls1_received_encrypted = ''; +var tls2_received_encrypted = ''; + +var handshake_done = false; +var tls1_ended = false; +var tls2_ended = false; + +var duplex1 = new stream.Duplex(); +var duplex2 = new stream.Duplex(); + +duplex1._write = function(chunk, callback, onwrite) { + duplex2.push(chunk); + onwrite(); +}; + +duplex2._write = function(chunk, callback, onwrite) { + duplex1.push(chunk); + onwrite(); +}; + +duplex1._readyToWrite(); +duplex2._readyToWrite(); + +var server_opts = { + key: fs.readFileSync(process.cwd() + '/resources/my_key.key').toString(), + cert: fs.readFileSync(process.cwd() + '/resources/my_crt.crt').toString(), + isServer: true, + rejectUnauthorized: false, +}; + +var client_opts = { + rejectUnauthorized: false, +}; + +var tls1 = new tls.TLSSocket(duplex1, server_opts); +var tls2 = new tls.TLSSocket(duplex2, client_opts); + +tls2.on('secureConnect', function() { + handshake_done = true; +}); + +tls1.on('data', function(data) { + tls1_received_message += data.toString(); + tls1.end(); +}); + +tls1._socket.on('data', function(data) { + tls1_received_encrypted += data.toString('hex'); +}); + +tls2.on('data', function(data) { + tls2_received_message += data.toString(); + tls2.write(tls2_message); +}); + +tls2._socket.on('data', function(data) { + tls2_received_encrypted += data.toString('hex'); +}); + +tls1.on('end', function() { + tls1_ended = true; + tls2.end(); +}); + +tls2.on('end', function() { + tls2_ended = true; +}); + +tls1.write(tls1_message); + +process.on('exit', function() { + assert.equal(tls1_received_message === tls2_expected_message, true); + assert.equal(tls2_received_message === tls1_expected_message, true); + assert.equal(tls1_received_encrypted === tls2_message, false); + assert.equal(tls2_received_encrypted === tls1_message, false); + assert.equal(handshake_done === true, true); + assert.equal(tls1_ended === true, true); + assert.equal(tls2_ended === true, true); +}); diff --git a/test/run_pass/test_uart.js b/test/run_pass/test_uart.js index c3ba71ea6c..3b2ef0e7e6 100644 --- a/test/run_pass/test_uart.js +++ b/test/run_pass/test_uart.js @@ -13,38 +13,27 @@ * limitations under the License. */ -var assert = require('assert'); -var Uart = require('uart'); - -var uart = new Uart(); +var uart = require('uart'); +var pin = require('tools/systemio_common').pin; +var checkError = require('tools/systemio_common').checkError; var configuration = { + device: pin.uart1, // for Linux, TizenRT and Nuttx + port: pin.uart1, // for Tizen baudRate: 115200, - dataBits: 8 + dataBits: 8, }; -if (process.platform === 'linux') { - configuration.device = '/dev/ttyS0'; -} else if (process.platform === 'nuttx') { - configuration.device = '/dev/ttyS1'; -} else if (process.platform === 'tizenrt') { - configuration.device = '/dev/ttyDBG'; -} else { - assert.fail(); -} - writeTest(); function writeTest() { - var serial = uart.open(configuration, function(err) { - assert.equal(err, null); - console.log('open done'); + var serial = uart.openSync(configuration); + console.log('open done'); - serial.writeSync("Hello IoT.js.\n\r"); - serial.closeSync(); - console.log('close done'); - writeReadTest(); - }); + serial.writeSync('Hello IoT.js.\n\r'); + serial.closeSync(); + console.log('close done'); + writeReadTest(); } function writeReadTest() { @@ -52,7 +41,7 @@ function writeReadTest() { var write = 0; var serial = uart.open(configuration, function(err) { - assert.equal(err, null); + checkError(err); console.log('open done'); serial.on('data', function(data) { @@ -65,16 +54,17 @@ function writeReadTest() { } }); - serial.write("Hello there?\n\r", function(err) { - assert.equal(err, null); + serial.write('Hello there?\n\r', function(err) { + checkError(err); console.log('write done'); write = 1; if (read && write) { - serial.close(); + serial.close(function(err) { + checkError(err); + }); console.log('close done'); } }); }); } - diff --git a/test/run_pass/test_process_readsource.js b/test/run_pass/test_uart_api.js similarity index 68% rename from test/run_pass/test_process_readsource.js rename to test/run_pass/test_uart_api.js index a582d448f8..c4c4098850 100644 --- a/test/run_pass/test_process_readsource.js +++ b/test/run_pass/test_uart_api.js @@ -14,14 +14,10 @@ */ var assert = require('assert'); +var uart = require('uart'); -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"); +// ------ Test API existence +assert.equal(typeof uart.open, 'function', + 'uart does not provide \'open\' function'); +assert.equal(typeof uart.openSync, 'function', + 'uart does not provide \'openSync\' function'); diff --git a/test/run_pass/test_websocket.js b/test/run_pass/test_websocket.js new file mode 100644 index 0000000000..8027e50d34 --- /dev/null +++ b/test/run_pass/test_websocket.js @@ -0,0 +1,53 @@ +/* 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 ws = require('websocket'); +var assert = require('assert'); + +var websocket = new ws.Websocket(); + +var connected = false; +var message_sent = 'Hello IoT.js WebSocket'; +var message_received = null; +var ping_sent = 'IoT.js ping message'; +var ping_received = null; +var close_string = 'Connection successfully closed'; + +websocket.connect('ws://echo.websocket.org', 80, '/', function() { + connected = true; + + this.on('message', function(msg){ + message_received = msg.toString(); + }); + + this.ping(ping_sent, true, function(msg) { + ping_received = msg.toString(); + }); + + this.on('close', function(msg) { + assert.equal(msg.code, '1000'); + assert.equal(msg.reason, close_string); + }); + + this.send(message_sent, {mask: true, binary: false}) + this.close(close_string, 1000); +}); + + +process.on('exit', function() { + assert.equal(connected, true); + assert.equal(message_received, message_sent); + assert.equal(ping_sent, ping_received); +}); diff --git a/test/run_pass/test_websocket_headercheck.js b/test/run_pass/test_websocket_headercheck.js new file mode 100644 index 0000000000..0a776bc51f --- /dev/null +++ b/test/run_pass/test_websocket_headercheck.js @@ -0,0 +1,54 @@ +/* Copyright 2019-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 ws = require('websocket'); +var http = require('http'); + +var websocket = new ws.Websocket(); + +var test_connected = false; +var test_statuscode = -1; + +var server = new ws.Server({ port: 8001 }, function(srv) { + console.log("Connected!"); + test_connected = true; + server.close() +}); + +var client = http.request({ + method: 'GET', + port: 8001, + headers: { + // Test if multiple values for the Connection header is accepted + 'Connection': 'keep-alive, Upgrade', + 'Upgrade': 'websocket', + 'Sec-WebSocket-Key': 'r3UXMybFKTPGuT2CK5cYGw==', + 'Sec-WebSocket-Version': 13, + } +}, function(response) { + // 101 Switching Protocols + test_statuscode = response.statusCode; + server.close(); +}); + +client.end(); + + +process.on('exit', function () { + assert(test_connected, 'WebScoket server did not received connection event'); + assert.equal(test_statusCode, 101, + 'GET with multiple Connection value should return 101 status'); +}); diff --git a/test/run_pass/test_websocket_server.js b/test/run_pass/test_websocket_server.js new file mode 100644 index 0000000000..836d2a300c --- /dev/null +++ b/test/run_pass/test_websocket_server.js @@ -0,0 +1,126 @@ +/* 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 websocket = require('websocket'); +var assert = require('assert'); +var http = require('http'); + +var client = new websocket.Websocket(); +var client2 = new websocket.Websocket(); +var client3 = new websocket.Websocket(); +var message_sent = 'Hello IoT.js WebSocket'; +var ping_sent = 'IoT.js ping message'; +var close_string = 'Connection successfully closed'; +var close_code = 1000; + +function listener(ws) { + ws.on('message', function(msg) { + assert.equal(message_sent, msg.toString(), + 'Message received by the Server'); + // echo + ws.send(msg.toString(), {mask: true, binary: false}); + }); + ws.on('ping', function(msg) { + assert.equal(ping_sent, msg.toString(), + 'Ping received by the Server'); + }); +} + + +// Test two clients connection +var options = { + port: 8081, +}; + +var wss = new websocket.Server(options, listener); +var address = wss.address(); + +wss.on('close', function(msg) { + assert.equal(close_string, msg.reason, + 'Close reason received by the Server1'); + assert.equal(close_code, msg.code, + 'Close code received by the Server1'); + assert.equal(address.address, '0.0.0.0', 'Address of Server1'); + assert.equal(address.family, 'IPv4', 'Ip family of Server1'); + assert.equal(address.port, '8081', 'Port of Server1'); +}); + +client.connect('ws://localhost', 8081, '/', function() { + this.on('message', function(msg) { + assert.equal(message_sent, msg.toString(), + 'Message received by the Client1'); + }); + + this.ping(ping_sent, true, function(msg) { + assert.equal(ping_sent, msg.toString(), + 'Ping received by the Client1'); + }); + + this.on('close', function(msg) { + assert.equal(close_string, msg.reason, + 'Close reason received by the Client1'); + assert.equal(close_code, msg.code, + 'Close code received by the Client1'); + }); + + // Client2 connect + client2.connect('ws://localhost', 8081, '/'); + client2.on('open', function() { + // Broadcast then terminate all clients and close the server + wss.broadcast(message_sent); + wss.close(); + }); + + this.send(message_sent, {mask: true, binary: false}); +}); + + +// Test http server upgrade to websocket +var httpServer = http.createServer().listen(8082); + +options = { + server: httpServer, +}; + +var wss2 = new websocket.Server(options, listener); + +wss2.on('close', function(msg) { + assert.equal(close_string, msg.reason, + 'Close reason received by the Server2'); + assert.equal(close_code, msg.code, + 'Close code received by the Server2'); +}); + +client3.connect('ws://localhost', 8082, '/', function() { + this.on('message', function(msg) { + assert.equal(message_sent, msg.toString(), + 'Message received by the Client3'); + wss2.close(); + }); + + this.ping(ping_sent, true, function(msg) { + assert.equal(ping_sent, msg.toString(), + 'Ping received by the Client3'); + }); + + this.on('close', function(msg) { + assert.equal(close_string, msg.reason, + 'Close reason received by the Client3'); + assert.equal(close_code, msg.code, + 'Close code received by the Client3'); + }); + + this.send(message_sent, {mask: true, binary: false}); +}); diff --git a/test/run_pass/test_websocket_server_secure.js b/test/run_pass/test_websocket_server_secure.js new file mode 100644 index 0000000000..1a737a7945 --- /dev/null +++ b/test/run_pass/test_websocket_server_secure.js @@ -0,0 +1,140 @@ +/* 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 websocket = require('websocket'); +var assert = require('assert'); +var fs = require('fs'); +var tls = require('tls'); +var key = fs.readFileSync(process.cwd() + + '/resources/my_key.key').toString(); +var cert = fs.readFileSync(process.cwd() + + '/resources/my_crt.crt'); + +var client = new websocket.Websocket(); +var client2 = new websocket.Websocket(); +var client3 = new websocket.Websocket(); +var message_sent = 'Hello IoT.js WebSocket'; +var ping_sent = 'IoT.js ping message'; +var close_string = 'Connection successfully closed'; +var close_code = 1000; + +function listener(ws) { + ws.on('message', function(msg) { + assert.equal(message_sent, msg.toString(), + 'Message received by the Server'); + // echo + ws.send(msg.toString(), {mask: true, binary: false}); + }); + ws.on('ping', function(msg) { + assert.equal(ping_sent, msg.toString(), + 'Ping received by the Server'); + }); +} + + +// Test two clients connection +var options = { + port: 8081, + secure: true, + key: key, + cert: cert, +}; + +var wss = new websocket.Server(options, listener); +var address = wss.address(); + +wss.on('close', function(msg) { + assert.equal(close_string, msg.reason, + 'Close reason received by the Server1'); + assert.equal(close_code, msg.code, + 'Close code received by the Server1'); + assert.equal(address.address, '0.0.0.0', 'Address of Server1'); + assert.equal(address.family, 'IPv4', 'Ip family of Server1'); + assert.equal(address.port, '8081', 'Port of Server1'); +}); + +client.connect('wss://localhost', 8081, '/', function() { + this.on('message', function(msg) { + assert.equal(message_sent, msg.toString(), + 'Message received by the Client1'); + }); + + this.ping(ping_sent, true, function(msg) { + assert.equal(ping_sent, msg.toString(), + 'Ping received by the Client1'); + }); + + this.on('close', function(msg) { + assert.equal(close_string, msg.reason, + 'Close reason received by the Client1'); + assert.equal(close_code, msg.code, + 'Close code received by the Client1'); + }); + + // Client2 connect + client2.connect('wss://localhost', 8081, '/'); + client2.on('open', function() { + // Broadcast then terminate all clients and close the server + wss.broadcast(message_sent); + wss.close(); + }); + + this.send(message_sent, {mask: true, binary: false}); +}); + + +// Test tls server upgrade to websocket +var tlsOptions = { + key: key, + cert: cert, + isServer: true, +}; + +var tlsServer = tls.createServer(tlsOptions).listen(8082); + +options = { + server: tlsServer, +}; + +var wss2 = new websocket.Server(options, listener); + +wss2.on('close', function(msg) { + assert.equal(close_string, msg.reason, + 'Close reason received by the Server2'); + assert.equal(close_code, msg.code, + 'Close code received by the Server2'); +}); + +client3.connect('wss://localhost', 8082, '/', function() { + this.on('message', function(msg) { + assert.equal(message_sent, msg.toString(), + 'Message received by the Client3'); + wss2.close(); + }); + + this.ping(ping_sent, true, function(msg) { + assert.equal(ping_sent, msg.toString(), + 'Ping received by the Client3'); + }); + + this.on('close', function(msg) { + assert.equal(close_string, msg.reason, + 'Close reason received by the Client3'); + assert.equal(close_code, msg.code, + 'Close code received by the Client3'); + }); + + this.send(message_sent, {mask: true, binary: false}); +}); diff --git a/test/testsets.json b/test/testsets.json index ca5a8fb1d7..d7f5bad348 100644 --- a/test/testsets.json +++ b/test/testsets.json @@ -1,126 +1,1412 @@ { - "run_pass": [ - { "name": "test_adc.js", "skip": ["all"], "reason": "need to setup test environment" }, - { "name": "test_assert.js" }, - { "name": "test_ble_advertisement.js", "skip": ["all"], "reason": "need to setup test environment" }, - { "name": "test_ble_setservices.js", "skip": ["all"], "reason": "need to setup test environment" }, - { "name": "test_ble_setservices_central.js", "skip": ["all"], "reason": "run it with nodejs after running test_ble_setservices.js" }, - { "name": "test_buffer_builtin.js" }, - { "name": "test_buffer.js" }, - { "name": "test_console.js" }, - { "name": "test_dgram_1_server_1_client.js", "skip": ["all"], "reason": "need to setup test environment" }, - { "name": "test_dgram_1_server_n_clients.js", "skip": ["all"], "reason": "need to setup test environment" }, - { "name": "test_dgram_address.js", "skip": ["all"], "reason": "need to setup test environment" }, - { "name": "test_dgram_broadcast.js", "skip": ["all"], "reason": "need to setup test environment" }, - { "name": "test_dgram_multicast_membership.js", "skip": ["all"], "reason": "need to setup test environment" }, - { "name": "test_dgram_multicast_set_multicast_loop.js", "skip": ["all"], "reason": "need to setup test environment" }, - { "name": "test_dgram_setttl_client.js", "skip": ["all"], "reason": "need to setup test environment" }, - { "name": "test_dgram_setttl_server.js", "skip": ["all"], "reason": "need to setup test environment" }, - { "name": "test_dns.js" }, - { "name": "test_dns_lookup.js", "skip": ["nuttx"], "reason": "not implemented for nuttx" }, - { "name": "test_events.js" }, - { "name": "test_events_assert_emit_error.js", "uncaught": true }, - { "name": "test_events_uncaught_error.js", "uncaught": true }, - { "name": "test_fs_exists.js" }, - { "name": "test_fs_exists_sync.js" }, - { "name": "test_fs_fstat.js", "skip": ["nuttx"], "reason": "not implemented for nuttx" }, - { "name": "test_fs_fstat_sync.js", "skip": ["nuttx"], "reason": "not implemented for nuttx" }, - { "name": "test_fs_mkdir_rmdir.js", "skip": ["nuttx"], "reason": "implemented, run manually in default configuration" }, - { "name": "test_fs_open_close.js", "skip": ["nuttx"], "reason": "not implemented for nuttx" }, - { "name": "test_fs_readdir.js", "skip": ["nuttx"], "reason": "not implemented for nuttx" }, - { "name": "test_fs_readfile.js" }, - { "name": "test_fs_readfile_sync.js" }, - { "name": "test_fs_rename.js" }, - { "name": "test_fs_rename_sync.js" }, - { "name": "test_fs_stat.js" }, - { "name": "test_fs_write.js", "skip": ["nuttx"], "reason": "not implemented for nuttx" }, - { "name": "test_fs_writefile.js" }, - { "name": "test_fs_writefile_sync.js" }, - { "name": "test_fs_writefile_unlink.js" }, - { "name": "test_fs_writefile_unlink_sync.js" }, - { "name": "test_fs_event.js", "skip": ["nuttx"], "reason": "not implemented for nuttx" }, - { "name": "test_fs_open_read.js" }, - { "name": "test_fs_open_read_sync_1.js", "skip": ["nuttx"], "reason": "not implemented for nuttx" }, - { "name": "test_fs_open_read_sync_2.js" }, - { "name": "test_fs_open_read_sync_3.js" }, - { "name": "test_gpio_input.js", "skip": ["all"], "reason": "needs hardware" }, - { "name": "test_gpio_output.js", "skip": ["all"], "reason": "need user input"}, - { "name": "test_i2c.js", "skip": ["all"], "reason": "need to setup test environment" }, - { "name": "test_iotjs_promise.js", "skip": ["all"], "reason": "es2015 is off by default" }, - { "name": "test_module_cache.js", "skip": ["nuttx"], "reason": "not implemented for nuttx" }, - { "name": "test_module_require.js", "skip": ["nuttx"], "reason": "not implemented for nuttx" }, - { "name": "test_net_1.js" }, - { "name": "test_net_2.js" }, - { "name": "test_net_3.js", "timeout": 100, "skip": ["nuttx"], "reason": "requires too many socket descriptors and too large buffers" }, - { "name": "test_net_4.js" }, - { "name": "test_net_5.js" }, - { "name": "test_net_6.js" }, - { "name": "test_net_7.js", "skip": ["nuttx"], "reason": "requires too many socket descriptors" }, - { "name": "test_net_8.js" }, - { "name": "test_net_9.js" }, - { "name": "test_net_10.js" }, - { "name": "test_net_connect.js", "timeout": 10 }, - { "name": "test_net_headers.js" }, - { "name": "test_net_http_get.js", "timeout": 20 }, - { "name": "test_net_http_response_twice.js", "timeout": 10 }, - { "name": "test_net_http_request_response.js", "timeout": 10, "skip": ["nuttx"], "reason": "not implemented for nuttx" }, - { "name": "test_net_http_status_codes.js", "timeout": 20, "skip": ["nuttx"], "reason": "not implemented for nuttx" }, - { "name": "test_net_httpclient_error.js", "timeout": 10, "skip": ["nuttx"], "reason": "not implemented for nuttx" }, - { "name": "test_net_httpclient_parse_error.js", "timeout": 10 }, - { "name": "test_net_httpclient_timeout_1.js", "timeout": 10 }, - { "name": "test_net_httpclient_timeout_2.js", "timeout": 15 }, - { "name": "test_net_httpserver_timeout.js", "timeout": 10 }, - { "name": "test_net_httpserver.js", "timeout": 20, "skip": ["nuttx"], "reason": "not implemented for nuttx" }, - { "name": "test_process.js" }, - { "name": "test_process_chdir.js" }, - { "name": "test_process_cwd.js" }, - { "name": "test_process_exit.js" }, - { "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", "uncaught": true }, - { "name": "test_process_uncaught_simple.js", "uncaught": true }, - { "name": "test_pwm.js", "skip": ["all"], "reason": "need to setup test environment" }, - { "name": "test_spi.js", "skip": ["all"], "reason": "need to setup test environment" }, - { "name": "test_stream.js" }, - { "name": "test_stream_duplex.js"}, - { "name": "test_timers_arguments.js" }, - { "name": "test_timers_error.js" }, - { "name": "test_timers_simple.js", "timeout": 10 }, - { "name": "test_uart.js", "skip": ["all"], "reason": "need to setup test environment" }, - { "name": "test_util.js" } + "run_pass": [ + { + "name": "test_adc.js", + "skip": [ + "all" + ], + "reason": "need to setup test environment", + "required-modules": [ + "adc" + ] + }, + { + "name": "test_assert.js" + }, + { + "name": "test_ble_advertisement.js", + "skip": [ + "all" + ], + "reason": "need to setup test environment", + "required-modules": [ + "ble" + ] + }, + { + "name": "test_ble_setservices.js", + "skip": [ + "all" + ], + "reason": "need to setup test environment", + "required-modules": [ + "ble" + ] + }, + { + "name": "test_ble_setservices_central.js", + "skip": [ + "all" + ], + "reason": "run it with nodejs after running test_ble_setservices.js" + }, + { + "name": "test_buffer.js" + }, + { + "name": "test_buffer_from.js" + }, + { + "name": "test_buffer_from_arraybuffer.js", + "required-features": [ + "ArrayBuffer" + ] + }, + { + "name": "test_buffer_str_conv.js" + }, + { + "name": "test_buffer_inmutability_creation.js" + }, + { + "name": "test_console.js", + "required-modules": [ + "console" + ] + }, + { + "name": "test_crypto.js", + "required-modules": [ + "crypto" + ] + }, + { + "name": "test_crypto_tls.js", + "required-modules": [ + "crypto", + "fs", + "tls" + ] + }, + { + "name": "test_dgram_1_server_1_client.js", + "required-modules": [ + "dgram" + ] + }, + { + "name": "test_dgram_1_server_n_clients.js", + "skip": [ + "linux" + ], + "reason": "[linux]: flaky on Travis", + "required-modules": [ + "dgram" + ] + }, + { + "name": "test_dgram_address.js", + "required-modules": [ + "dgram" + ] + }, + { + "name": "test_dgram_broadcast.js", + "skip": [ + "all" + ], + "reason": "need to setup test environment", + "required-modules": [ + "dgram" + ] + }, + { + "name": "test_dgram_multicast_membership.js", + "skip": [ + "all" + ], + "reason": "need to setup test environment", + "required-modules": [ + "dgram" + ] + }, + { + "name": "test_dgram_multicast_set_multicast_loop.js", + "required-modules": [ + "dgram" + ] + }, + { + "name": "test_dgram_setttl_client.js", + "skip": [ + "all" + ], + "reason": "need to setup test environment", + "required-modules": [ + "dgram" + ] + }, + { + "name": "test_dgram_setttl_server.js", + "skip": [ + "all" + ], + "reason": "need to setup test environment", + "required-modules": [ + "dgram" + ] + }, + { + "name": "test_dns.js", + "required-modules": [ + "net" + ] + }, + { + "name": "test_dns_lookup.js", + "required-modules": [ + "dns" + ] + }, + { + "name": "test_events.js", + "required-modules": [ + "events" + ] + }, + { + "name": "test_events_assert_emit_error.js", + "required-modules": [ + "events" + ] + }, + { + "name": "test_events_uncaught_error.js", + "required-modules": [ + "events" + ] + }, + { + "name": "test_fs_exists.js", + "required-modules": [ + "fs" + ] + }, + { + "name": "test_fs_exists_sync.js", + "required-modules": [ + "fs" + ] + }, + { + "name": "test_fs_fstat.js", + "skip": [ + "nuttx", + "tizenrt" + ], + "reason": "not implemented for nuttx/TizenRT", + "required-modules": [ + "fs" + ] + }, + { + "name": "test_fs_fstat_sync.js", + "skip": [ + "nuttx", + "tizenrt" + ], + "reason": "not implemented for nuttx/TizenRT", + "required-modules": [ + "fs" + ] + }, + { + "name": "test_fs_mkdir_rmdir.js", + "skip": [ + "nuttx" + ], + "reason": "[nuttx]: implemented, run manually in default configuration", + "required-modules": [ + "fs" + ] + }, + { + "name": "test_fs_open_close.js", + "skip": [ + "nuttx" + ], + "reason": "not implemented for nuttx", + "required-modules": [ + "fs" + ] + }, + { + "name": "test_fs_read_stream.js", + "required-modules": [ + "fs" + ] + }, + { + "name": "test_fs_readdir.js", + "required-modules": [ + "fs" + ] + }, + { + "name": "test_fs_readfile.js", + "required-modules": [ + "fs" + ] + }, + { + "name": "test_fs_readfile_sync.js", + "required-modules": [ + "fs" + ] + }, + { + "name": "test_fs_rename.js", + "skip": [ + "nuttx" + ], + "reason": "depends on the type of the memory (testrunner uses Read Only Memory)", + "required-modules": [ + "fs" + ] + }, + { + "name": "test_fs_rename_sync.js", + "skip": [ + "nuttx" + ], + "reason": "depends on the type of the memory (testrunner uses Read Only Memory)", + "required-modules": [ + "fs" + ] + }, + { + "name": "test_fs_stat.js", + "required-modules": [ + "fs" + ] + }, + { + "name": "test_fs_stream_pipe.js", + "skip": [ + "all" + ], + "reason": "flaky on Travis", + "required-modules": [ + "fs" + ] + }, + { + "name": "test_fs_write.js", + "skip": [ + "nuttx" + ], + "reason": "not implemented for nuttx", + "required-modules": [ + "fs" + ] + }, + { + "name": "test_fs_write_stream.js", + "skip": [ + "nuttx" + ], + "reason": "depends on the type of the memory (testrunner uses Read Only Memory)", + "required-modules": [ + "fs" + ] + }, + { + "name": "test_fs_writefile.js", + "skip": [ + "nuttx" + ], + "reason": "depends on the type of the memory (testrunner uses Read Only Memory)", + "required-modules": [ + "fs" + ] + }, + { + "name": "test_fs_writefile_sync.js", + "skip": [ + "nuttx" + ], + "reason": "depends on the type of the memory (testrunner uses Read Only Memory)", + "required-modules": [ + "fs" + ] + }, + { + "name": "test_fs_writefile_unlink.js", + "skip": [ + "nuttx" + ], + "reason": "depends on the type of the memory (testrunner uses Read Only Memory)", + "required-modules": [ + "fs" + ] + }, + { + "name": "test_fs_writefile_unlink_sync.js", + "skip": [ + "nuttx" + ], + "reason": "depends on the type of the memory (testrunner uses Read Only Memory)", + "required-modules": [ + "fs" + ] + }, + { + "name": "test_fs_event.js", + "skip": [ + "nuttx" + ], + "reason": "not implemented for nuttx", + "required-modules": [ + "fs" + ] + }, + { + "name": "test_fs_open_read.js", + "required-modules": [ + "fs" + ] + }, + { + "name": "test_fs_open_read_sync_1.js", + "skip": [ + "nuttx" + ], + "reason": "not implemented for nuttx", + "required-modules": [ + "fs" + ] + }, + { + "name": "test_fs_open_read_sync_2.js", + "required-modules": [ + "fs" + ] + }, + { + "name": "test_fs_open_read_sync_3.js", + "required-modules": [ + "fs" + ] + }, + { + "name": "test_gpio_api.js", + "skip": [ + "linux", "nuttx", "tizen", "tizenrt", "windows" + ], + "reason": "need to setup test environment", + "required-modules": [ + "gpio" + ] + }, + { + "name": "test_gpio_direction.js", + "skip": [ + "all" + ], + "reason": "need to setup test environment", + "required-modules": [ + "gpio" + ] + }, + { + "name": "test_gpio_input.js", + "skip": [ + "all" + ], + "reason": "need to setup test environment", + "required-modules": [ + "gpio" + ] + }, + { + "name": "test_gpio_output.js", + "skip": [ + "linux", "nuttx", "tizen", "tizenrt", "windows" + ], + "reason": "need to setup test environment", + "required-modules": [ + "gpio" + ] + }, + { + "name": "test_http_signature.js", + "required-modules": [ + "http_signature" + ] + }, + { + "name": "test_i2c_api.js", + "skip": [ + "linux", "nuttx", "tizen", "tizenrt", "windows" + ], + "reason": "need to setup test environment", + "required-modules": [ + "i2c" + ] + }, + { + "name": "test_i2c_gy30.js", + "skip": [ + "all" + ], + "reason": "need to setup test environment", + "required-modules": [ + "i2c" + ] + }, + { + "name": "test_iotjs_promise.js", + "required-features": [ + "Promise" + ] + }, + { + "name": "test_iotjs_promise_chain_calls.js", + "required-modules": [ + "fs" + ], + "required-features": [ + "Promise" + ] + }, + { + "name": "test_module_cache.js" + }, + { + "name": "test_module_json.js" + }, + { + "name": "test_module_require.js" + }, + { + "name": "test_mqtt.js", + "required-modules": [ + "mqtt" + ] + }, + { + "name": "test_mqtt_frags.js", + "required-modules": [ + "mqtt" + ] + }, + { + "name": "test_net_1.js", + "required-modules": [ + "net" + ] + }, + { + "name": "test_net_2.js", + "required-modules": [ + "net" + ] + }, + { + "name": "test_net_3.js", + "skip": [ + "nuttx" + ], + "reason": "[nuttx]: requires too many socket descriptors and too large buffers", + "required-modules": [ + "net" + ] + }, + { + "name": "test_net_4.js", + "required-modules": [ + "net", + "timers" + ] + }, + { + "name": "test_net_5.js", + "required-modules": [ + "net", + "timers" + ] + }, + { + "name": "test_net_6.js", + "required-modules": [ + "net", + "timers" + ] + }, + { + "name": "test_net_7.js", + "skip": [ + "nuttx" + ], + "reason": "requires too many socket descriptors", + "required-modules": [ + "net", + "timers" + ] + }, + { + "name": "test_net_8.js", + "required-modules": [ + "net", + "timers" + ] + }, + { + "name": "test_net_9.js", + "required-modules": [ + "net" + ] + }, + { + "name": "test_net_10.js", + "required-modules": [ + "net" + ] + }, + { + "name": "test_net_connect.js", + "required-modules": [ + "net" + ] + }, + { + "name": "test_net_headers.js", + "required-modules": [ + "http" + ] + }, + { + "name": "test_net_http_get.js", + "required-modules": [ + "http" + ] + }, + { + "name": "test_net_http_outgoing_buffer.js", + "required-modules": [ + "http" + ] + }, + { + "name": "test_net_http_methods.js", + "required-modules": [ + "http" + ] + }, + { + "name": "test_net_http_response_twice.js", + "required-modules": [ + "http", + "net" + ] + }, + { + "name": "test_net_http_request_response.js", + "skip": [ + "nuttx" + ], + "reason": "not implemented for nuttx", + "required-modules": [ + "http", + "net" + ] + }, + { + "name": "test_net_http_request_http_version.js", + "required-modules": [ + "http" + ] + }, + { + "name": "test_net_http_status_codes.js", + "required-modules": [ + "http" + ] + }, + { + "name": "test_net_http_modified_request.js", + "required-modules": [ + "http" + ] + }, + { + "name": "test_net_http_modified_response.js", + "required-modules": [ + "http" + ] + }, + { + "name": "test_net_http_modified_req_resp.js", + "required-modules": [ + "http" + ] + }, + { + "name": "test_net_httpclient_error.js", + "required-modules": [ + "http" + ] + }, + { + "name": "test_net_httpclient_parse_error.js", + "required-modules": [ + "http", + "net" + ] + }, + { + "name": "test_net_httpclient_timeout_1.js", + "required-modules": [ + "http", + "net" + ] + }, + { + "name": "test_net_httpclient_timeout_2.js", + "required-modules": [ + "http" + ] + }, + { + "name": "test_net_http_server_timeout.js", + "required-modules": [ + "http" + ] + }, + { + "name": "test_net_http_server.js", + "required-modules": [ + "http" + ] + }, + { + "name": "test_net_https_get.js", + "timeout": 10, + "required-modules": [ + "https" + ] + }, + { + "name": "test_net_https_post_status_codes.js", + "timeout": 10, + "required-modules": [ + "https" + ] + }, + { + "name": "test_net_https_request_response.js", + "timeout": 10, + "required-modules": [ + "https", + "http", + "net" + ] + }, + { + "name": "test_net_https_modified_req_resp.js", + "required-modules": [ + "https", + "http", + "net" + ] + }, + { + "name": "test_net_https_timeout.js", + "timeout": 10, + "required-modules": [ + "https" + ] + }, + { + "name": "test_net_https_server.js", + "timeout": 10, + "required-modules": [ + "https", + "fs" + ] + }, + { + "name": "test_process.js" + }, + { + "name": "test_process_chdir.js" + }, + { + "name": "test_process_cwd.js" + }, + { + "name": "test_process_exit.js" + }, + { + "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_uncaught_order.js" + }, + { + "name": "test_process_uncaught_simple.js" + }, + { + "name": "test_pwm_api.js", + "skip": [ + "linux", "nuttx", "tizen", "tizenrt", "windows" + ], + "reason": "need to setup test environment", + "required-modules": [ + "pwm" + ] + }, + { + "name": "test_pwm_async.js", + "skip": [ + "linux", "nuttx", "tizen", "tizenrt", "windows" + ], + "reason": "need to setup test environment", + "required-modules": [ + "pwm" + ] + }, + { + "name": "test_pwm_sync.js", + "skip": [ + "linux", "nuttx", "tizen", "tizenrt", "windows" + ], + "reason": "need to setup test environment", + "required-modules": [ + "pwm" + ] + }, + { + "name": "test_spi.js", + "skip": [ + "linux" + ], + "reason": "Different env on Linux desktop/travis/rpi", + "required-modules": [ + "spi" + ] + }, + { + "name": "test_spi_buffer_async.js", + "skip": [ + "all" + ], + "reason": "need to setup test environment", + "required-modules": [ + "spi" + ] + }, + { + "name": "test_spi_buffer_sync.js", + "skip": [ + "all" + ], + "reason": "need to setup test environment", + "required-modules": [ + "spi" + ] + }, + { + "name": "test_spi_mcp3008.js", + "skip": [ + "all" + ], + "reason": "need to setup test environment", + "required-modules": [ + "spi" + ] + }, + { + "name": "test_stream.js", + "required-modules": [ + "stream" + ] + }, + { + "name": "test_stream_duplex.js", + "required-modules": [ + "stream" + ] + }, + { + "name": "test_stream_pipe.js", + "required-modules": [ + "stream" + ] + }, + { + "name": "test_timers_arguments.js" + }, + { + "name": "test_timers_error.js" + }, + { + "name": "test_timers_simple.js", + "timeout": 10 + }, + { + "name": "test_tizen_app_control.js", + "skip": [ + "all" + ], + "reason": "need to setup test environment", + "required-modules": [ + "tizen" + ] + }, + { + "name": "test_tls_1.js", + "required-modules": [ + "tls", + "fs" + ] + }, + { + "name": "test_tls_2.js", + "required-modules": [ + "tls", + "fs" + ] + }, + { + "name": "test_tls_3.js", + "required-modules": [ + "tls", + "fs" + ] + }, + { + "name": "test_tls_4.js", + "required-modules": [ + "tls", + "fs" + ] + }, + { + "name": "test_tls_ca.js", + "required-modules": [ + "tls", + "fs" + ] + }, + { + "name": "test_tls_stream_duplex.js", + "required-modules": [ + "tls", + "fs", + "stream" + ] + }, + { + "name": "test_uart.js", + "skip": [ + "all" + ], + "reason": "need to setup test environment", + "required-modules": [ + "uart" + ] + }, + { + "name": "test_uart_api.js", + "required-modules": [ + "uart" + ] + }, + { + "name": "test_util.js", + "required-modules": [ + "util" + ] + }, + { + "name": "test_websocket.js", + "required-modules": [ + "websocket" + ] + }, + { + "name": "test_websocket_server.js", + "required-modules": [ + "websocket" + ] + }, + { + "name": "test_websocket_server_secure.js", + "required-modules": [ + "websocket", + "tls" + ] + } ], "run_pass/issue": [ - { "name": "issue-133.js" }, - { "name": "issue-137.js" }, - { "name": "issue-198.js" }, - { "name": "issue-223.js" }, - { "name": "issue-266.js" }, - { "name": "issue-323.js" }, - { "name": "issue-816.js" } + { + "name": "issue-133.js" + }, + { + "name": "issue-137.js" + }, + { + "name": "issue-198.js" + }, + { + "name": "issue-223.js", + "required-modules": [ + "net" + ] + }, + { + "name": "issue-266.js", + "required-modules": [ + "net" + ] + }, + { + "name": "issue-323.js", + "required-modules": [ + "fs" + ] + }, + { + "name": "issue-816.js", + "required-modules": [ + "buffer" + ] + }, + { + "name": "issue-1046.js", + "required-modules": [ + "buffer" + ] + }, + { + "name": "issue-1077.js" + }, + { + "name": "issue-1101.js", + "skip": [ + "all" + ], + "reason": "need to setup test environment", + "required-modules": [ + "uart" + ] + }, + { + "name": "issue-1348.js" + }, + { + "name": "issue-1463.js", + "required-features": [ + "Promise" + ] + }, + { + "name": "issue-1485.js" + }, + { + "name": "issue-1507.js", + "required-modules": [ + "console" + ] + }, + { + "name": "issue-1557.js" + }, + { + "name": "issue-1897.js", + "required-modules": [ + "websocket" + ] + }, + { + "name": "issue-1904.js", + "required-modules": [ + "dgram" + ] + } ], - "run_fail": [ - { "name": "test_assert_equal.js", "expected-failure": true }, - { "name": "test_assert_fail.js", "expected-failure": true }, - { "name": "test_assert_notequal.js", "expected-failure": true }, - { "name": "test_events_emit_error.js", "expected-failure": true }, - { "name": "test_fs_callbacks_called.js", "expected-failure": true }, - { "name": "test_iotjs_runtime_error.js", "expected-failure": true }, - { "name": "test_iotjs_syntax_error.js", "expected-failure": true }, - { "name": "test_module_require_invalid_file.js", "expected-failure": true }, - { "name": "test_process_exitcode_arg.js", "expected-failure": true }, - { "name": "test_process_exitcode_var.js", "expected-failure": true }, - { "name": "test_process_explicit_exit.js", "expected-failure": true }, - { "name": "test_process_implicit_exit.js", "expected-failure": true } + "run_fail": [ + { + "name": "test_assert_equal.js", + "expected-failure": true + }, + { + "name": "test_assert_fail.js", + "expected-failure": true + }, + { + "name": "test_assert_notequal.js", + "expected-failure": true + }, + { + "name": "test_events_emit_error.js", + "expected-failure": true, + "required-modules": [ + "events" + ] + }, + { + "name": "test_fs_callbacks_called.js", + "expected-failure": true, + "required-modules": [ + "fs" + ] + }, + { + "name": "test_iotjs_runtime_error.js", + "expected-failure": true + }, + { + "name": "test_iotjs_syntax_error.js", + "expected-failure": true + }, + { + "name": "test-issue-1349.js", + "expected-failure": true, + "required-modules": [ + "dns" + ] + }, + { + "name": "test-issue-1360.js", + "expected-failure": true + }, + { + "name": "test-issue-1570.js", + "expected-failure": true + }, + { + "name": "test-issue-1915.js", + "expected-failure": true, + "required-modules": [ + "uart" + ] + }, + { + "name": "test_module_require_invalid_file.js", + "expected-failure": true + }, + { + "name": "test_module_require_path_below_root.js", + "expected-failure": true + }, + { + "name": "test_process_exitcode_arg.js", + "expected-failure": true + }, + { + "name": "test_process_exitcode_var.js", + "expected-failure": true + }, + { + "name": "test_process_explicit_exit.js", + "expected-failure": true + }, + { + "name": "test_process_implicit_exit.js", + "expected-failure": true + }, + { + "name": "test_timers_issue_1353.js", + "expected-failure": true + }, + { + "name": "test-issue-1917.js", + "expected-failure": true, + "required-modules": [ + "fs" + ] + } ], "node/parallel": [ - { "name": "test-assert.js" }, - { "name": "test-http-status-message.js" }, - { "name": "test-http-write-head.js" }, - { "name": "test-net-bind-twice.js" }, - { "name": "test-net-end-without-connect.js" }, - { "name": "test-net-keepalive.js" }, - { "name": "test-timers-clear-null-does-not-throw-error.js" } + { + "name": "test-assert.js", + "required-modules": [ + "fs", + "stream" + ] + }, + { + "name": "test-module-circular.js", + "required-modules": [ + "fs", + "stream" + ] + }, + { + "name": "test-http-catch-uncaughtexception.js", + "required-modules": [ + "http", + "fs", + "stream" + ] + }, + { + "name": "test-http-status-message.js", + "required-modules": [ + "http", + "net", + "fs", + "stream" + ] + }, + { + "name": "test-http-write-head.js", + "required-modules": [ + "http", + "fs", + "stream" + ] + }, + { + "name": "test-net-bind-twice.js", + "required-modules": [ + "net", + "fs", + "stream" + ] + }, + { + "name": "test-net-end-without-connect.js", + "required-modules": [ + "net", + "fs", + "stream" + ] + }, + { + "name": "test-net-keepalive.js", + "required-modules": [ + "net", + "fs", + "stream" + ] + }, + { + "name": "test-timers-clear-null-does-not-throw-error.js", + "required-modules": [ + "fs", + "stream" + ] + } + ], + "external_modules": [ + { + "name": "test-external-module1.js", + "required-modules": [ + "mymodule1" + ] + }, + { + "name": "test-external-module2.js", + "required-modules": [ + "mymodule2" + ] + } + ], + "napi": [ + { + "name": "test_napi_arguments_return.js", + "required-modules": [ + "napi" + ] + }, + { + "name": "test_napi_arguments_return_this.js", + "required-modules": [ + "napi" + ] + }, + { + "name": "test_napi_arguments_throw.js", + "required-modules": [ + "napi" + ] + }, + { + "name": "test_napi_array.js", + "required-modules": [ + "napi" + ] + }, + { + "name": "test_napi_async.js", + "required-modules": [ + "napi" + ] + }, + { + "name": "test_napi_buffer.js", + "required-modules": [ + "napi" + ] + }, + { + "name": "test_napi_construct.js", + "required-modules": [ + "napi" + ] + }, + { + "name": "test_napi_conversions.js", + "required-modules": [ + "napi" + ] + }, + { + "name": "test_napi_create_error.js", + "required-modules": [ + "napi" + ] + }, + { + "name": "test_napi_dataview.js", + "required-features": [ + "ArrayBuffer", + "DataView" + ], + "required-modules": [ + "napi" + ] + }, + { + "name": "test_napi_env.js", + "required-modules": [ + "napi" + ] + }, + { + "name": "test_napi_exception.js", + "required-modules": [ + "napi" + ] + }, + { + "name": "test_napi_general.js", + "required-modules": [ + "napi" + ] + }, + { + "name": "test_napi_general_es2015.js", + "required-features": [ + "ArrayBuffer", + "Promise", + "Symbol", + "TypedArray" + ], + "required-modules": [ + "napi" + ] + }, + { + "name": "test_napi_handle_scope.js", + "required-modules": [ + "napi" + ] + }, + { + "name": "test_napi_is_error.js", + "required-modules": [ + "napi" + ] + }, + { + "name": "test_napi_make_callback.js", + "required-modules": [ + "napi" + ] + }, + { + "name": "test_napi_make_callback_error.js", + "required-modules": [ + "napi" + ] + }, + { + "name": "test_napi_object_wrap.js", + "required-modules": [ + "napi" + ] + }, + { + "name": "test_napi_properties.js", + "required-modules": [ + "napi" + ] + }, + { + "name": "test_napi_reference.js", + "required-modules": [ + "napi" + ] + }, + { + "name": "test_napi_promise.js", + "required-modules": [ + "napi" + ], + "required-features": [ + "Promise" + ] + }, + { + "name": "test_napi_strictequal_and_instanceof.js", + "required-modules": [ + "napi" + ] + }, + { + "name": "test_napi_string.js", + "required-modules": [ + "napi" + ] + }, + { + "name": "test_napi_symbol.js", + "required-features": [ + "Symbol" + ], + "required-modules": [ + "napi" + ] + }, + { + "name": "test_napi_throw_error.js", + "required-modules": [ + "napi" + ] + }, + { + "name": "test_napi_throw.js", + "required-modules": [ + "napi" + ] + }, + { + "name": "test_napi_typedarray.js", + "required-features": [ + "ArrayBuffer", + "TypedArray" + ], + "required-modules": [ + "napi" + ] + } ] } diff --git a/test/tools/iotjs_build_info.js b/test/tools/iotjs_build_info.js new file mode 100644 index 0000000000..73b703accf --- /dev/null +++ b/test/tools/iotjs_build_info.js @@ -0,0 +1,84 @@ +/* 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. + */ + +/* Just for the testrunner to get runtime information about the build. */ +var builtins = process.builtin_modules; + +if (process.env.IOTJS_ENV.indexOf("experimental") > -1) + stability = "experimental" +else + stability = "stable" + +/* Check if certain es2015 features are available */ +function hasFeatures(object, features) { + supported = true; + + for (feature in features) { + supported = supported && object.hasOwnProperty(features[feature]); + } + + return supported; +} + +function hasArrowFunction() { + try { + eval("a => {}"); + return true; + } catch(e) {} + + return false; +} + +var features = {}; + +var typedArrayFeatures = [ + 'Int8Array', + 'Uint8Array', + 'Uint8ClampedArray', + 'Int16Array', + 'Uint16Array', + 'Int32Array', + 'Uint32Array', + 'Float32Array', + 'Float64Array' +]; + +if (hasFeatures(global, ['Symbol'])) + features.Symbol = true; + +if (hasFeatures(global, ['Promise'])) + features.Promise = true; + +if (hasFeatures(global, ['ArrayBuffer'])) + features.ArrayBuffer = true; + +if (hasFeatures(global, ['DataView'])) + features.DataView = true; + +if (hasFeatures(global, typedArrayFeatures)) + features.TypedArray = true; + +if (hasArrowFunction()) + features.ArrowFunction = true; + +result = { + 'builtins': builtins, + 'features': features, + 'stability': stability, + 'debug': !!process.debug, + 'arch': process.arch +} + +console.log(JSON.stringify(result)) diff --git a/test/tools/systemio_common.js b/test/tools/systemio_common.js new file mode 100644 index 0000000000..97c37c0750 --- /dev/null +++ b/test/tools/systemio_common.js @@ -0,0 +1,69 @@ +/* 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 pin = {}; + +if (process.platform === 'linux') { + pin.led = 20; + pin.switch = 13; + pin.pwm1 = 0; + pin.i2c1 = '/dev/i2c-1'; + pin.spi1 = '/dev/spidev0.0'; + pin.uart1 = '/dev/ttyS0'; +} else if (process.platform === 'tizen') { + 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; +} else if (process.platform === 'nuttx') { + var board = process.iotjs.board; + var stm32_pin = require(board).pin; + pin.led = stm32_pin.PA10; + pin.switch = stm32_pin.PA15; + pin.pwm1 = stm32_pin.PWM1.CH1_1; + pin.i2c1 = 1; + pin.spi1 = 1; + pin.uart1 = '/dev/ttyS1'; +} else if (process.platform === 'tizenrt') { + pin.led = 41; + pin.switch = 39; + pin.pwm1 = 0; + pin.i2c1 = 1; + pin.spi1 = 1; + pin.uart1 = '/dev/ttyS1'; +} else { + throw new Error('Unsupported platform'); +} + +function checkError(err) { + if (err) { + console.log('Have an error: ' + err.message); + assert.fail(); + } +} + +exports.pin = pin; +exports.checkError = checkError; diff --git a/tools/apt-get-install-deps.sh b/tools/apt-get-install-deps.sh index e7045d7a7a..b0dab17bdc 100755 --- a/tools/apt-get-install-deps.sh +++ b/tools/apt-get-install-deps.sh @@ -16,4 +16,4 @@ sudo apt-get update -q sudo apt-get install -q -y \ - cmake gcc valgrind clang-format-3.8 + cmake gcc valgrind clang-format-3.9 diff --git a/tools/apt-get-install-nuttx.sh b/tools/apt-get-install-nuttx.sh index 012d01f4fd..08153cba7d 100755 --- a/tools/apt-get-install-nuttx.sh +++ b/tools/apt-get-install-nuttx.sh @@ -17,5 +17,5 @@ sudo apt-get update -q sudo apt-get install -q -y \ autoconf libtool gperf flex bison autoconf2.13 \ - cmake libncurses-dev libusb-1.0-0-dev \ + cmake libncurses-dev libusb-1.0-0-dev genromfs \ libsgutils2-dev gcc-arm-none-eabi diff --git a/tools/apt-get-install-tizenrt.sh b/tools/apt-get-install-tizenrt.sh new file mode 100755 index 0000000000..1abf8d0485 --- /dev/null +++ b/tools/apt-get-install-tizenrt.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +# 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. + + +sudo apt-get update +sudo apt-get install gcc-arm-none-eabi +arm-none-eabi-gcc --version diff --git a/tools/build.py b/tools/build.py index 471cd53f96..2108ea09c0 100755 --- a/tools/build.py +++ b/tools/build.py @@ -27,16 +27,14 @@ import re import os -from js2c import js2c -from module_analyzer import resolve_modules, analyze_module_dependency from common_py import path from common_py.system.filesystem import FileSystem as fs from common_py.system.executor import Executor as ex -from common_py.system.platform import Platform +from common_py.system.executor import Terminal +from common_py.system.sys_platform import Platform platform = Platform() - # Initialize build options. def init_options(): # Check config options. @@ -46,161 +44,164 @@ def init_options(): if arg_config: config_path = arg_config[-1].split('=', 1)[1] + build_config = {} + with open(config_path, 'rb') as f: + build_config = json.loads(f.read().decode('ascii')) + # Read config file and apply it to argv. argv = [] - with open(config_path, 'rb') as f: - config = json.loads(f.read().decode('ascii')) - config_option = config['build_option'] - for opt_key in config_option: - opt_val = config_option[opt_key] - if isinstance(opt_val, basestring) and opt_val != '': - argv.append('--%s=%s' % (opt_key, opt_val)) - elif isinstance(opt_val, bool): - if opt_val: - argv.append('--%s' % opt_key) - elif isinstance(opt_val, int): - argv.append('--%s=%s' % (opt_key, opt_val)) - elif isinstance(opt_val, list): - for val in opt_val: - argv.append('--%s=%s' % (opt_key, val)) + + list_with_commas = ['external-modules'] + + for opt_key in build_config: + opt_val = build_config[opt_key] + if (opt_key in list_with_commas) and isinstance(opt_val, list): + opt_val and argv.append('--%s=%s' % (opt_key, ','.join(opt_val))) + elif isinstance(opt_val, basestring) and opt_val != '': + argv.append(str('--%s=%s' % (opt_key, opt_val))) + elif isinstance(opt_val, bool): + if opt_val: + argv.append('--%s' % opt_key) + elif isinstance(opt_val, int): + argv.append('--%s=%s' % (opt_key, opt_val)) + elif isinstance(opt_val, list): + for val in opt_val: + argv.append('--%s=%s' % (opt_key, val)) # Apply command line argument to argv. argv = argv + sys.argv[1:] # Prepare argument parser. - parser = argparse.ArgumentParser() - - parser.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, + parser = argparse.ArgumentParser(description='Building tool for IoT.js ' + 'JavaScript framework for embedded systems.') + + 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', type=str.lower, + 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('--target-arch', - choices=['arm', 'x86', 'i686', 'x86_64', 'x64'], - 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'], - default=platform.os(), - help='Specify the target os: %(choices)s (default: %(default)s)') - - parser.add_argument('--target-board', - choices=['none', 'artik10', 'stm32f4dis', 'rpi2', 'artik05x'], - default='none', help='Specify the targeted 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('--cross-compile', dest='cross_compile', - action='store', help='Specify the cross compilation toolkit prefix.') - 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-static-lib', + iotjs_group.add_argument('--external-lib', action='append', default=[], - help='Specify additional external static library ' + help='Specify additional external library ' '(can be used multiple times)') - parser.add_argument('--external-shared-lib', + 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 external shared library ' - '(can be used multiple times)') + help='Specify additional linker flags (can be used multiple times)') + iotjs_group.add_argument('--n-api', + action='store_true', default=False, + help='Enable to build N-API feature') + 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', 'stm32f7nucleo', + 'rpi2', 'rpi3', 'artik05x'], + default=None, help='Specify the target board (default: %(default)s).') + iotjs_group.add_argument('--target-os', + choices=['linux', 'darwin', 'osx', 'mock', 'nuttx', 'tizen', 'tizenrt', + 'openwrt', 'windows'], + default=platform.os(), + help='Specify the target OS (default: %(default)s).') + iotjs_group.add_argument('--expose-gc', + action='store_true', default=False, + help='Expose the JerryScript\'s GC call to JavaScript') - parser.add_argument('--iotjs-include-module', - action='store', default=set(), type=lambda x: set(x.split(',')), - help='Specify iotjs modules which should be included ' - '(format: module_1,module_2,...)') - parser.add_argument('--iotjs-exclude-module', - action='store', default=set(), type=lambda x: set(x.split(',')), - help='Specify iotjs modules which should be excluded ' - '(format: module_1,module_2,...)') - parser.add_argument('--iotjs-minimal-profile', - action='store_true', default=False, - help='Build IoT.js with minimal profile') - 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', - type=int, default=config['build_option']['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', - action='store_true', default=False, - help='Enable JerryScript heap statistics') - - parser.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('--jerry-debugger-port', - type=int, default=5001, - help='Specify the port of JerryScript-debugger (default: %(default)s)') - 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('--no-check-test', - action='store_true', default=False, - help='Disable test exection after build') - parser.add_argument('--no-parallel-build', - action='store_true', default=False, - help='Disable parallel build') - parser.add_argument('--no-snapshot', + 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='Disable snapshot generation for IoT.js') - parser.add_argument('-e', '--experimental', + help='Build JerryScript with LTO enabled') + jerry_group.add_argument('--jerry-memstat', action='store_true', default=False, - help='Enable to build experimental features') + help='Enable JerryScript heap statistics') + jerry_group.add_argument('--jerry-profile', + metavar='FILE', action='store', default='es5.1', + help='Specify the profile for JerryScript (default: %(default)s). ' + 'Possible values are "es5.1", "es.next" or an absolute ' + 'path to a custom JerryScript profile file.') + jerry_group.add_argument('--js-backtrace', + choices=['ON', 'OFF'], type=str.upper, + help='Enable/disable backtrace information of JavaScript code ' + '(default: ON in debug and OFF in release build)') options = parser.parse_args(argv) - options.config = config + options.config = build_config return options @@ -210,7 +211,7 @@ def adjust_options(options): if options.target_os in ['nuttx', 'tizenrt']: options.buildlib = True if not options.sysroot: - ex.fail('--sysroot needed for nuttx target') + ex.fail('--sysroot needed for %s target' % options.target_os) options.sysroot = fs.abspath(options.sysroot) if not fs.exists(options.sysroot): @@ -224,47 +225,30 @@ def adjust_options(options): if options.target_os == 'darwin': options.no_check_valgrind = True - if options.target_board in ['rpi2', 'artik10', 'artik05x']: + if options.target_board in ['rpi2', 'rpi3', 'artik10', 'artik05x']: options.no_check_valgrind = True - elif options.target_board == 'none': - options.target_board = None - - if options.iotjs_minimal_profile: - options.no_check_test = True # Then add calculated options. options.host_tuple = '%s-%s' % (platform.arch(), platform.os()) options.target_tuple = '%s-%s' % (options.target_arch, options.target_os) - options.host_build_root = fs.join(path.PROJECT_ROOT, - options.builddir, - 'host', - options.host_tuple, - options.buildtype) - options.host_build_bins = fs.join(options.host_build_root, 'bin') + # Normalize the path of build directory. + options.builddir = fs.normpath(options.builddir) options.build_root = fs.join(path.PROJECT_ROOT, options.builddir, options.target_tuple, options.buildtype) - options.build_bins = fs.join(options.build_root, 'bin') - options.build_libs = fs.join(options.build_root, 'lib') cmake_path = fs.join(path.PROJECT_ROOT, 'cmake', 'config', '%s.cmake') options.cmake_toolchain_file = cmake_path % options.target_tuple - options.host_cmake_toolchain_file = cmake_path % options.host_tuple - - # Specify the file of JerryScript profile. - options.jerry_profile = fs.join(path.JERRY_PROFILE_ROOT, - options.jerry_profile + '.profile') - -def print_build_option(options): - print('=================================================') - option_vars = vars(options) - for opt in option_vars: - print(' --%s: %s' % (opt, option_vars[opt])) - print() + # Set the default value of '--js-backtrace' if it is not defined. + if not options.js_backtrace: + if options.buildtype == 'debug': + options.js_backtrace = "ON" + else: + options.js_backtrace = "OFF" def print_progress(msg): @@ -276,34 +260,22 @@ def init_submodule(): ex.check_run_cmd('git', ['submodule', 'update']) -def build_cmake_args(options, for_jerry=False): +def build_cmake_args(options): cmake_args = [] # compile flags - compile_flags = [] - - config_compile_flags = options.config['compile_flags'] - compile_flags += config_compile_flags['os'][options.target_os] - compile_flags += config_compile_flags['arch'][options.target_arch] - compile_flags += config_compile_flags['buildtype'][options.buildtype] - if options.target_board: - compile_flags += config_compile_flags['board'][options.target_board] - - compile_flags += options.compile_flag - compile_flags += options.jerry_compile_flag if for_jerry else [] + compile_flags = options.compile_flag + compile_flags += options.jerry_compile_flag - cmake_args.append("-DCMAKE_C_FLAGS='%s'" % (' '.join(compile_flags))) + cmake_args.append("-DEXTERNAL_COMPILE_FLAGS='%s'" % + (' '.join(compile_flags))) # link flags - link_flags = [] - - config_link_flags = options.config['link_flags'] - link_flags += config_link_flags['os'][options.target_os] - link_flags += options.link_flag + link_flags = options.link_flag if options.jerry_lto: link_flags.append('-flto') - cmake_args.append("-DCMAKE_EXE_LINKER_FLAGS='%s'" % (' '.join(link_flags))) + cmake_args.append("-DEXTERNAL_LINKER_FLAGS='%s'" % (' '.join(link_flags))) # external include dir include_dirs = [] @@ -311,9 +283,15 @@ def build_cmake_args(options, for_jerry=False): include_dirs.append('%s/include' % options.sysroot) if options.target_board == 'stm32f4dis': include_dirs.append('%s/arch/arm/src/stm32' % options.sysroot) + elif options.target_board == 'stm32f7nucleo': + include_dirs.append('%s/arch/arm/src/stm32f7' % options.sysroot) if options.target_os == 'tizenrt': include_dirs.append('%s/../framework/include/iotbus' % options.sysroot) + elif options.target_os == 'windows': + cmake_args.append("-GVisual Studio 15 2017") + if options.target_arch == "x86_64": + cmake_args.append("-Ax64") include_dirs.extend(options.external_include_dir) cmake_args.append("-DEXTERNAL_INCLUDE_DIR='%s'" % (' '.join(include_dirs))) @@ -344,23 +322,23 @@ def build_iotjs(options): cmake_opt = [ '-B%s' % options.build_root, '-H%s' % path.PROJECT_ROOT, - "-DCMAKE_TOOLCHAIN_FILE='%s'" % options.cmake_toolchain_file, + "-DCMAKE_TOOLCHAIN_FILE=%s" % options.cmake_toolchain_file, '-DCMAKE_BUILD_TYPE=%s' % options.buildtype.capitalize(), + '-DTARGET_ARCH=%s' % options.target_arch, '-DTARGET_OS=%s' % options.target_os, '-DTARGET_BOARD=%s' % options.target_board, - '-DPLATFORM_DESCRIPTOR=%s' % options.target_tuple, '-DENABLE_LTO=%s' % get_on_off(options.jerry_lto), # --jerry-lto + '-DENABLE_MODULE_NAPI=%s' % get_on_off(options.n_api), # --n-api '-DENABLE_SNAPSHOT=%s' % get_on_off(not options.no_snapshot), - '-DENABLE_MINIMAL=%s' % get_on_off(options.iotjs_minimal_profile), - '-DBUILD_LIB_ONLY=%s' % get_on_off(options.buildlib), # --build-lib + '-DEXPOSE_GC=%s' % get_on_off(options.expose_gc), # --exposing gc + '-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), - # --iotjs-include-module - "-DIOTJS_INCLUDE_MODULE='%s'" % ','.join(options.iotjs_include_module), - # --iotjs-exclude-module - "-DIOTJS_EXCLUDE_MODULE='%s'" % ','.join(options.iotjs_exclude_module), + '-DJERRY_MEM_STATS=%s' % get_on_off(options.jerry_memstat), + # --external-modules + "-DEXTERNAL_MODULES='%s'" % ';'.join(options.external_modules), # --jerry-profile - "-DFEATURE_PROFILE='%s'" % options.jerry_profile, + "-DJERRY_PROFILE='%s'" % options.jerry_profile, ] if options.target_os in ['nuttx', 'tizenrt']: @@ -371,31 +349,31 @@ def build_iotjs(options): # --jerry-heaplimit if options.jerry_heaplimit: - cmake_opt.append('-DMEM_HEAP_SIZE_KB=%d' % options.jerry_heaplimit) + cmake_opt.append('-DJERRY_GLOBAL_HEAP_SIZE=%d' % + options.jerry_heaplimit) + if options.jerry_heaplimit > 512: + cmake_opt.append("-DEXTRA_JERRY_CMAKE_PARAMS='%s'" % + "-DJERRY_CPOINTER_32_BIT=ON") # --jerry-heap-section if options.jerry_heap_section: - cmake_opt.append("-DJERRY_HEAP_SECTION_ATTR='%s'" % + cmake_opt.append("-DJERRY_ATTR_GLOBAL_HEAP='%s'" % options.jerry_heap_section) # --jerry-debugger if options.jerry_debugger: - cmake_opt.append('-DFEATURE_DEBUGGER=ON') - cmake_opt.append('-DFEATURE_DEBUGGER_PORT=%d' % - options.jerry_debugger_port) + cmake_opt.append("-DJERRY_DEBUGGER=ON") + + # --js-backtrace + cmake_opt.append("-DJERRY_LINE_INFO=%s" % + options.js_backtrace) # --cmake-param cmake_opt.extend(options.cmake_param) - # --external-static-lib - cmake_opt.append("-DEXTERNAL_STATIC_LIB='%s'" % - (' '.join(options.external_static_lib))) - - # --external-shared-lib - shared_libs = [] - shared_libs.extend(options.external_shared_lib) - shared_libs.extend(options.config['shared_libs']['os'][options.target_os]) - cmake_opt.append("-DEXTERNAL_SHARED_LIB='%s'" % (' '.join(shared_libs))) + # --external-lib + cmake_opt.append("-DEXTERNAL_LIBS='%s'" % + (' '.join(options.external_lib))) # --jerry-cmake-param if options.jerry_cmake_param: @@ -404,7 +382,11 @@ def build_iotjs(options): # --experimental if options.experimental: - options.compile_flag.append('-DEXPERIMENTAL') + cmake_opt.append('-DEXPERIMENTAL=ON') + + # --profile + if options.profile: + cmake_opt.append("-DIOTJS_PROFILE='%s'" % options.profile) # Add common cmake options. cmake_opt.extend(build_cmake_args(options)) @@ -412,51 +394,29 @@ def build_iotjs(options): # Run cmake. ex.check_run_cmd('cmake', cmake_opt) - run_make(options, options.build_root) - - -def process_modules(options): - print_progress('Analyze modules') - - includes, excludes = resolve_modules(options) - modules = analyze_module_dependency(includes, excludes) - - print('Selected js modules: %s' % ', '.join(modules['js'])) - print('Selected native modules: %s' % ', '.join(modules['native'])) - - options.js_modules = modules['js'] - options.native_modules = modules['native'] - options.iotjs_exclude_module = excludes + if options.target_os == 'windows': + print("\nPlease open the iot.js solution file in Visual Studio!") + else: + run_make(options, options.build_root) def run_checktest(options): - checktest_quiet = 'yes' - if os.getenv('TRAVIS') == "true": - checktest_quiet = 'no' - # IoT.js executable iotjs = fs.join(options.build_root, 'bin', 'iotjs') - build_args = ['quiet=' + checktest_quiet] - if options.iotjs_exclude_module: - skip_module = ','.join(options.iotjs_exclude_module) - build_args.append('skip-module=' + skip_module) - # experimental - if options.experimental: - build_args.append('experimental=' + 'yes'); + cmd = fs.join(path.TOOLS_ROOT, 'testrunner.py') + args = [iotjs, "--platform=%s" % options.target_os] + + if options.run_test == "quiet": + args.append('--quiet') fs.chdir(path.PROJECT_ROOT) - code = ex.run_cmd(iotjs, [path.CHECKTEST_PATH] + build_args) + code = ex.run_cmd(cmd, args) if code != 0: ex.fail('Failed to pass unit tests') + if not options.no_check_valgrind: - code = ex.run_cmd('valgrind', ['--leak-check=full', - '--error-exitcode=5', - '--undef-value-errors=no', - iotjs, - path.CHECKTEST_PATH] + build_args) - if code == 5: - ex.fail('Failed to pass valgrind test') + code = ex.run_cmd(cmd, ['--valgrind'] + args) if code != 0: ex.fail('Failed to pass unit tests in valgrind environment') @@ -465,14 +425,14 @@ def run_checktest(options): # Initialize build option object. options = init_options() adjust_options(options) - print_build_option(options) if options.clean: - print_progress('Clear build directory') + print_progress('Clear build directories') + test_build_root = fs.join(path.TEST_ROOT, + 'napi', + 'build') + fs.rmtree(test_build_root) fs.rmtree(options.build_root) - fs.rmtree(options.host_build_root) - - process_modules(options) # Perform init-submodule. if not options.no_init_submodule: @@ -481,16 +441,24 @@ def run_checktest(options): build_iotjs(options) + Terminal.pprint("\nIoT.js Build Succeeded!!\n", Terminal.green) + # Run tests. - if not options.no_check_test: + if options.run_test: print_progress('Run tests') if options.buildlib: print("Skip unit tests - build target is library\n") elif (options.host_tuple == options.target_tuple or (options.host_tuple == 'x86_64-linux' and - options.target_tuple == 'i686-linux')): + options.target_tuple == 'i686-linux') or + (options.host_tuple == 'x86_64-linux' and + options.target_tuple == 'x86_64-mock')): run_checktest(options) else: print("Skip unit tests - target-host pair is not allowed\n") - - print("\n%sIoT.js Build Succeeded!!%s\n" % (ex._TERM_GREEN, ex._TERM_EMPTY)) + else: + Terminal.pprint("\nTo run tests use '--run-test' " + "or one of the following commands:", + Terminal.blue) + print("\n tools/testrunner.py %s/%s/%s/bin/iotjs\n" + % (options.builddir, options.target_tuple, options.buildtype)) diff --git a/tools/check_license.py b/tools/check_license.py index d9ddececa9..37b34cc7cd 100755 --- a/tools/check_license.py +++ b/tools/check_license.py @@ -16,25 +16,35 @@ import re +from common_py import path +from common_py.system.filesystem import FileSystem as fs + +EXCLUDE_DIRS = [ + 'test/napi' +] class CheckLicenser(object): _license = re.compile( -u"""((#|//|\*) Copyright .* Samsung Electronics Co., Ltd. and other contribu.*)+ -\s?\\2 -\s?\\2 Licensed under the Apache License, Version 2.0 \(the "License"\); -\s?\\2 you may not use this file except in compliance with the License. -\s?\\2 You may obtain a copy of the License at -\s?\\2 -\s?\\2 http://www.apache.org/licenses/LICENSE-2.0 -\s?\\2 -\s?\\2 Unless required by applicable law or agreed to in writing, software -\s?\\2 distributed under the License is distributed on an "AS IS" BASIS -\s?\\2 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -\s?\\2 See the License for the specific language governing permissions and -\s?\\2 limitations under the License.""") + r'((#|//|\*) Copyright .*\n' + r')+\s?\2\n' + r'\s?\2 Licensed under the Apache License, Version 2.0 \(the "License"\);\n' + r'\s?\2 you may not use this file except in compliance with the License.\n' + r'\s?\2 You may obtain a copy of the License at\n' + r'\s?\2\n' + r'\s?\2 http://www.apache.org/licenses/LICENSE-2.0\n' + r'\s?\2\n' + r'\s?\2 Unless required by applicable law or agreed to in writing, software\n' + r'\s?\2 distributed under the License is distributed on an "AS IS" BASIS\n' + r'\s?\2 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n' + r'\s?\2 See the License for the specific language governing permissions and\n' + r'\s?\2 limitations under the License.\n' + ) @staticmethod def check(filename): + if any(fs.relpath(filename).startswith(exclude) for exclude in EXCLUDE_DIRS): + return True + with open(filename, 'r') as f: contents = f.read() return bool(CheckLicenser._license.search(contents)) diff --git a/tools/check_sonarqube.sh b/tools/check_sonarqube.sh new file mode 100755 index 0000000000..e861ff00b7 --- /dev/null +++ b/tools/check_sonarqube.sh @@ -0,0 +1,27 @@ +#!/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 [[ "${TRAVIS_REPO_SLUG}" == "jerryscript-project/iotjs" + && ${TRAVIS_BRANCH} == "master" + && ${TRAVIS_EVENT_TYPE} == "push" ]] +then + git fetch --unshallow + build-wrapper-linux-x86-64 --out-dir bw-output ./tools/build.py + sonar-scanner -Dsonar.projectVersion="${TRAVIS_COMMIT}" +else + echo "Skip: The pull request from ${TRAVIS_PULL_REQUEST_SLUG} is an \ + external one. It's not supported yet in Travis-CI" +fi diff --git a/tools/check_test.js b/tools/check_test.js deleted file mode 100644 index 52c7d1ee64..0000000000 --- a/tools/check_test.js +++ /dev/null @@ -1,262 +0,0 @@ -/* Copyright 2016-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 fs = require('fs'); -var Runner = require('test_runner').Runner; -var Logger = require('common_js/logger').Logger; -var OptionParser = require('common_js/option_parser').OptionParser; -var util = require('common_js/util'); -var EventEmitter = require('events').EventEmitter; - -var root = 'test'; -var parent = '..'; - -function Driver() { - this.results = { - pass: 0, - fail: 0, - skip: 0, - timeout: 0, - }; - - this.emitter = new EventEmitter(); - this.emitter.addListener('nextTest', function(driver, status, test) { - if (driver.runner) { - driver.runner.cleanup(); - } - var filename = test['name']; - - if (status == 'pass') { - driver.results.pass++; - driver.logger.message('PASS : ' + filename, status); - } else if (status == 'fail') { - driver.results.fail++; - driver.logger.message('FAIL : ' + filename, status); - } else if (status == 'skip') { - driver.results.skip++; - driver.logger.message('SKIP : ' + filename + - ' (reason : ' + test.reason + ")", status); - } else if (status == 'timeout') { - driver.results.timeout++; - driver.logger.message('TIMEOUT : ' + filename, status); - } - driver.fIdx++; - driver.runNextTest(); - }); - - this.os = process.platform; - this.board = process.iotjs.board; - - this.root = util.absolutePath(root); - process.chdir(this.root); - - return this; -} - -Driver.prototype.config = function() { - var parser = new OptionParser(); - - parser.addOption('start-from', "", "", - "a test case file name where the driver starts."); - parser.addOption('quiet', "yes|no", "yes", - "a flag that indicates if the driver suppresses " + - "console outputs of test case"); - parser.addOption('output-file', "", "", - "a file name where the driver leaves output"); - parser.addOption('skip-module', "", "", - "a module list to skip test of specific modules"); - parser.addOption('output-coverage', "yes|no", "no", - "output coverage information"); - parser.addOption('experimental', "yes|no", "no", - "a flag that indicates if tests for experimental are needed"); - - var options = parser.parse(); - - if (options == null) { - parser.printHelp(); - return false; - } - - var output = options['output-file']; - if (output) { - if (this.os == 'nuttx') { - var path = util.join('/mnt/sdcard', output); - } else { - var path = util.join(this.root, '..', output); - } - fs.writeFileSync(path, new Buffer('')); - } - var skipModule = options['skip-module']; - if (skipModule) { - this.skipModule = skipModule.split(','); - } - - var experimental = options['experimental']; - if (experimental == 'no') { - this.stability = 'stable'; - } else { - this.stability = 'experimental'; - } - - this.logger = new Logger(path); - - this.options = options; - - var testfile = util.join(this.root, 'testsets.json'); - var testsets = fs.readFileSync(testfile).toString(); - - this.tests = JSON.parse(testsets); - - this.dIdx = 0; - this.dLength = Object.keys(this.tests).length; - - var skipped = this.skipTestSet(options['start-from']); - - this.nextTestSet(skipped); - return true; -}; - -Driver.prototype.runNextTest = function() { - if (this.dIdx == this.dLength) { - this.finish(); - } else { - if (this.fIdx == this.fLength) { - this.dIdx++; - if (this.dIdx == this.dLength) { - this.finish(); - } else { - this.nextTestSet(); - this.runNextTest(); - } - } else { - this.runner = new Runner(this); - this.runner.run(); - } - } -}; - -Driver.prototype.skipTestSet = function(filename) { - if (!filename) - return false; - - var dLength = this.dLength; - for (var dIdx = 0; dIdx < dLength; dIdx++) { - var dirname = Object.keys(this.tests)[dIdx]; - var dir = this.tests[dirname]; - var fLength = dir.length; - for (var fIdx = 0; fIdx < fLength; fIdx++) { - if (dir[fIdx]['name'] == filename) { - this.fIdx = fIdx; - this.dIdx = dIdx; - return true; - } - } - } - - return false; -}; - -Driver.prototype.nextTestSet = function(skipped) { - if (!skipped) { - this.fIdx = 0; - } - - var dirname = this.dirname(); - this.fLength = this.tests[dirname].length; - this.logger.message("\n"); - this.logger.message(">>>> " + dirname, "summary"); -}; - -Driver.prototype.dirname = function() { - return Object.keys(this.tests)[this.dIdx] -}; - -Driver.prototype.currentTest = function() { - var dirname = this.dirname(); - return this.tests[dirname][this.fIdx]; -}; - -Driver.prototype.test = function() { - var test = this.currentTest(); - var dirname = this.dirname(); - var testfile = util.absolutePath(util.join(dirname, test['name'])); - - return fs.readFileSync(testfile).toString(); -}; - -Driver.prototype.finish = function() { - this.logger.message('\n\nfinish all tests', this.logger.status.summary); - - this.logger.message('PASS : ' + this.results.pass, this.logger.status.pass); - this.logger.message('FAIL : ' + this.results.fail, this.logger.status.fail); - this.logger.message('TIMEOUT : ' + - this.results.timeout, this.logger.status.timeout); - this.logger.message('SKIP : ' + this.results.skip, this.logger.status.skip); - - if (this.options["output-coverage"] == "yes" - && typeof __coverage__ !== "undefined") { - data = JSON.stringify(__coverage__); - - if (!fs.existsSync("../.coverage_output/")) { - fs.mkdirSync("../.coverage_output/"); - } - - fs.writeFileSync("../.coverage_output/js_coverage.data", Buffer(data)); - } - else if (this.results.fail > 0 || this.results.timeout > 0) { - originalExit(1); - } - - originalExit(0); -}; - -var driver = new Driver(); - -var originalExit = process.exit; -process.exit = function(code) { - // this function is called when the following happens. - // 1. the test case is finished normally. - // 2. assertion inside the callback function is failed. - var should_fail = driver.runner.test['expected-failure']; - try { - process.emitExit(code); - } catch(e) { - // when assertion inside the process.on('exit', function { ... }) is failed, - // this procedure is executed. - process.removeAllListeners('exit'); - - if (should_fail) { - driver.runner.finish('pass'); - } else { - console.error(e); - driver.runner.finish('fail'); - } - } finally { - process.removeAllListeners('exit'); - - if (code != 0 && !should_fail) { - driver.runner.finish('fail'); - } else if (code == 0 && should_fail) { - driver.runner.finish('fail'); - } else { - driver.runner.finish('pass'); - } - } -}; - -var conf = driver.config(); -if (conf) { - driver.runNextTest(); -} diff --git a/tools/check_tidy.py b/tools/check_tidy.py index 7b098f9023..79fb5b52d1 100755 --- a/tools/check_tidy.py +++ b/tools/check_tidy.py @@ -22,18 +22,20 @@ import os import subprocess import tempfile +import re from distutils import spawn from check_license import CheckLicenser from common_py.system.filesystem import FileSystem as fs from common_py.system.executor import Executor as ex +from common_py.system.executor import Terminal def parse_option(): parser = argparse.ArgumentParser() parser.add_argument('--autoedit', action='store_true', default=False, - help='Automatically edit the detected clang format errors.' + help='Automatically edit the detected clang format and eslint errors.' 'No diffs will be displayed') option = parser.parse_args() @@ -48,6 +50,8 @@ def __init__(self): self.count_lines = 0 self.count_empty_lines = 0 self.errors = [] + self.rules = [] + self.err_msgs = [] @property def error_count(self): @@ -62,26 +66,31 @@ def report_error(self, msg): line = fileinput.filelineno() self.errors.append("%s:%d: %s" % (name, line, msg)) + def set_rules(self): + limit = StyleChecker.column_limit + self.rules.append(re.compile(r"[\t]")) + self.err_msgs.append("TAB character") + self.rules.append(re.compile(r"[\r]")) + self.err_msgs.append("CR character") + self.rules.append(re.compile(r"[ \t]+[\n]$")) + self.err_msgs.append("Trailing Whitespace") + self.rules.append(re.compile(r"[^\n]\Z")) + self.err_msgs.append("Line ends without NEW LINE character") + self.rules.append(re.compile("^.{" + str(limit+1) + ",}")) + self.err_msgs.append("Line exceeds %d characters" % limit) + # append additional rules + def check(self, files): for line in fileinput.input(files): - if '\t' in line: - self.report_error('TAB character') - if '\r' in line: - self.report_error('CR character') - if line.endswith(' \n') or line.endswith('\t\n'): - self.report_error('trailing whitespace') - if not line.endswith('\n'): - self.report_error('line ends without NEW LINE character') - - if len(line) - 1 > StyleChecker.column_limit: - self.report_error('line exceeds %d characters' - % StyleChecker.column_limit) + for i, rule in enumerate(self.rules): + mc = rule.search(line) + if mc: + self.report_error(self.err_msgs[i]) if fileinput.isfirstline(): if not CheckLicenser.check(fileinput.filename()): self.report_error('incorrect license') - self.count_lines += 1 if not line.strip(): self.count_empty_lines += 1 @@ -94,7 +103,7 @@ def __init__(self, extensions, skip_files=None, options=None): self._extensions = extensions self._skip_files = skip_files self._options = options - self._check_clang_format("clang-format-3.8") + self._check_clang_format("clang-format-3.9") def _check_clang_format(self, base): clang_format = spawn.find_executable(base) @@ -102,11 +111,12 @@ def _check_clang_format(self, base): if not clang_format: clang_format = spawn.find_executable("clang-format") if clang_format: - print("%sUsing %s instead of %s%s" - % (ex._TERM_YELLOW, clang_format, base, ex._TERM_EMPTY)) + Terminal.pprint( + "Using %s instead of %s" % (clang_format, base), + Terminal.yellow) else: - print("%sNo %s found, skipping checks!%s" - % (ex._TERM_RED, base, ex._TERM_EMPTY)) + Terminal.pprint("No %s found, skipping checks!" % base, + Terminal.red) self._clang_format = clang_format @@ -126,9 +136,8 @@ def check(self, files): args = ['-style=file', file] if self._options and self._options.autoedit: args.append('-i') - output = ex.run_cmd_output(self._clang_format, - args, - quiet=True) + output = ex.check_run_cmd_output(self._clang_format, + args, quiet=True) if output: with tempfile.NamedTemporaryFile() as temp: @@ -145,6 +154,41 @@ def _diff(self, original, formatted): # the diff from that it. Otherwise nothing to do. self.diffs.append(error.output.decode()) +class EslintChecker(object): + + def __init__(self, options=None): + self._check_eslint() + self._options = options + + def _check_eslint(self): + self._node = spawn.find_executable('node') + if not self._node: + Terminal.pprint('No node found,', Terminal.red) + return + + self._eslint = spawn.find_executable('node_modules/.bin/eslint') + if not self._eslint: + self._eslint = spawn.find_executable('eslint') + if not self._eslint: + Terminal.pprint('No eslint found.', Terminal.red) + + def check(self): + self.error_count = 0 + + if not self._node or not self._eslint: + return + args = ['src', '-f', 'codeframe'] + if self._options and self._options.autoedit: + args.append('--fix') + + output = ex.run_cmd_output(self._eslint, args, quiet=True) + match = re.search('(\d+) error', output) + if match: + self.error_count = int(match.group(1)) + + # Delete unnecessary error messages. + self.errors = output.split('\n')[:-4] + class FileFilter(object): @@ -168,9 +212,11 @@ def check_tidy(src_dir, options=None): allowed_exts = ['.c', '.h', '.js', '.py', '.sh', '.cmake'] allowed_files = ['CMakeLists.txt'] clang_format_exts = ['.c', '.h'] - skip_dirs = ['deps', 'build', '.git', 'node_modules', 'coverage'] - skip_files = ['check_signed_off.sh', '__init__.py', + skip_dirs = ['deps', 'build', '.git', 'node_modules', 'coverage', + 'iotjs_modules', 'IoTjsApp'] + skip_files = ['check_license.py', 'check_signed_off.sh', '__init__.py', 'iotjs_js.c', 'iotjs_js.h', 'iotjs_string_ext.inl.h', + "iotjs_module_inl.h", 'ble.js', 'ble_hci_socket_acl_stream.js', 'ble_hci_socket_smp.js', @@ -180,17 +226,25 @@ def check_tidy(src_dir, options=None): 'ble_hci_socket_mgmt.js', 'ble_hci_socket_bindings.js', 'ble_characteristic.js', + 'node_api.h', + 'node_api_types.h', 'test_ble_setservices.js', + '.eslintrc.js', + 'c_source_templates.py', + 'cpp_source_templates.py' ] style = StyleChecker() + style.set_rules() clang = ClangFormat(clang_format_exts, skip_files, options) + eslint = EslintChecker(options) file_filter = FileFilter(allowed_exts, allowed_files, skip_files) files = fs.files_under(src_dir, skip_dirs, file_filter) clang.check(files) style.check(files) + eslint.check() if clang.error_count: print("Detected clang-format problems:") @@ -202,17 +256,24 @@ def check_tidy(src_dir, options=None): print("\n".join(style.errors)) print() - total_errors = style.error_count + clang.error_count + if eslint.error_count: + print("Detected eslint problems:") + print("\n".join(eslint.errors)) + print() + + total_errors = style.error_count + clang.error_count + eslint.error_count print("* total lines of code: %d" % style.count_lines) print("* total non-blank lines of code: %d" % style.count_valid_lines) print("* style errors: %d" % style.error_count) print("* clang-format errors: %d" % clang.error_count) + print("* eslint errors: %d" % eslint.error_count) - msg_color = ex._TERM_RED if total_errors > 0 else ex._TERM_GREEN - print("%s* total errors: %d%s" % (msg_color, total_errors, ex._TERM_EMPTY)) + msg_color = Terminal.red if total_errors > 0 else Terminal.green + Terminal.pprint("* total errors: %d" % (total_errors), msg_color) print() - return total_errors == 0 + if total_errors: + ex.fail("Failed tidy check") diff --git a/tools/common_js/logger.js b/tools/common_js/logger.js deleted file mode 100644 index 043eb31d5e..0000000000 --- a/tools/common_js/logger.js +++ /dev/null @@ -1,58 +0,0 @@ -/* Copyright 2016-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 fs = require('fs'); - -function Logger(path) { - this.text_colors = { - red: "\033[1;31m", - yellow: "\033[1;33m", - green: "\033[1;32m", - blue: "\033[1;34m", - empty: "\033[0m", - }; - this.status = { - pass: "pass", - skip: "skip", - fail: "fail", - timeout: "timeout", - summary: "summary" - } - this.path = path; - - return this; -} - -Logger.prototype.message = function (msg, status) { - if (this.path) { - // FIXME : After fs.appendFile is implemented, it should be replaced. - var data = fs.readFileSync(this.path); - var newData = data + msg + "\n"; - fs.writeFileSync(this.path, new Buffer(newData)); - } - if (status == this.status.pass) { - console.log(this.text_colors.green + msg + this.text_colors.empty); - } else if (status == this.status.skip) { - console.log(this.text_colors.yellow + msg + this.text_colors.empty); - } else if (status == this.status.fail || status == this.status.timeout){ - console.log(this.text_colors.red + msg + this.text_colors.empty); - } else if (status == this.status.summary){ - console.log(this.text_colors.blue + msg + this.text_colors.empty); - } else { - console.log(msg); - } -} - -module.exports.Logger = Logger; diff --git a/tools/common_js/option_parser.js b/tools/common_js/option_parser.js deleted file mode 100644 index dbdcc8bfe4..0000000000 --- a/tools/common_js/option_parser.js +++ /dev/null @@ -1,89 +0,0 @@ -/* Copyright 2016-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. - */ - -function Option(arg, value, default_value, help) { - this.arg = arg; - this.value = value; - this.default_value = default_value; - this.help = help; - - return this; -} - -Option.prototype.printHelp = function() { - console.log("\t" + this.arg + "=[" + this.value + "](default: " + - this.default_value + ") : " + this.help); -} - -function OptionParser() { - this.options = []; - return this; -} - -OptionParser.prototype.addOption = function(arg, value, default_value, help) { - var option = new Option(arg, value, default_value, help); - this.options.push(option); -} - -OptionParser.prototype.parse = function() { - var options = {}; - - for (var idx in this.options) { - var option = this.options[idx]; - var default_value = option.default_value; - if (default_value !== "") { - options[option.arg] = default_value; - } - } - - for (var aIdx = 2; aIdx < process.argv.length; aIdx++) { - var option = process.argv[aIdx]; - var arg_val = option.split("="); - - if (arg_val.length != 2 || !arg_val[0] || !arg_val[1]) { - return null; - } - - var arg = arg_val[0]; - var val = arg_val[1]; - var found = false; - - for (var oIdx in this.options) { - if (arg == this.options[oIdx].arg) { - options[arg] = val; - found = true; - break; - } - } - - if (!found) - return null; - } - - return options; -} - -OptionParser.prototype.printHelp = function() { - console.log(process.argv[1]); - console.log("\noptional arguments"); - for (var idx in this.options) { - this.options[idx].printHelp(); - } -} - - - - - module.exports.OptionParser = OptionParser; diff --git a/tools/common_js/util.js b/tools/common_js/util.js deleted file mode 100644 index ca797045f7..0000000000 --- a/tools/common_js/util.js +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright 2016-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. - */ - -function absolutePath(path) { - // FIXME: On NuttX side, when dealing with file, path should be absolute. - // So workaround this problem, test driver converts relative path - // to absolute one. - return process.cwd() + '/' + path; -} - -function join() { - var path = Array.prototype.join.call(arguments, '/'); - return path; -} - -module.exports.absolutePath = absolutePath; -module.exports.join = join; diff --git a/tools/common_py/path.py b/tools/common_py/path.py index b00ca52d8a..8d4a44bd7c 100644 --- a/tools/common_py/path.py +++ b/tools/common_py/path.py @@ -52,8 +52,8 @@ # Root directory for http-parser submodule. HTTPPARSER_ROOT = fs.join(DEPS_ROOT, 'http-parser') -# checktest -CHECKTEST_PATH = fs.join(TOOLS_ROOT, 'check_test.js') - # Build configuration file path. BUILD_CONFIG_PATH = fs.join(PROJECT_ROOT, 'build.config') + +# IoT.js build information. +BUILD_INFO_PATH = fs.join(TEST_ROOT, 'tools', 'iotjs_build_info.js') diff --git a/tools/common_py/system/executor.py b/tools/common_py/system/executor.py index a8d721e60a..b612b40b3e 100644 --- a/tools/common_py/system/executor.py +++ b/tools/common_py/system/executor.py @@ -14,15 +14,34 @@ from __future__ import print_function +import collections +import os import subprocess +_colors = { + "empty": "\033[0m", + "red": "\033[1;31m", + "green": "\033[1;32m", + "yellow": "\033[1;33m", + "blue": "\033[1;34m" +} + +if "TERM" not in os.environ: + # if there is no "TERM" environment variable + # assume that we can't output colors. + # So reset the ANSI color escapes. + _colors = _colors.fromkeys(_colors, "") + +_TerminalType = collections.namedtuple('Terminal', _colors.keys()) +class _Terminal(_TerminalType): + + def pprint(self, text, color=_colors["empty"]): + print("%s%s%s" % (color, text, self.empty)) + +Terminal = _Terminal(**_colors) + class Executor(object): - _TERM_RED = "\033[1;31m" - _TERM_YELLOW = "\033[1;33m" - _TERM_GREEN = "\033[1;32m" - _TERM_BLUE = "\033[1;34m" - _TERM_EMPTY = "\033[0m" @staticmethod def cmd_line(cmd, args=[]): @@ -30,28 +49,39 @@ def cmd_line(cmd, args=[]): @staticmethod def print_cmd_line(cmd, args=[]): - print("%s%s%s" % (Executor._TERM_BLUE, Executor.cmd_line(cmd, args), - Executor._TERM_EMPTY)) + Terminal.pprint(Executor.cmd_line(cmd, args), Terminal.blue) print() @staticmethod def fail(msg): print() - print("%s%s%s" % (Executor._TERM_RED, msg, Executor._TERM_EMPTY)) + Terminal.pprint(msg, Terminal.red) print() exit(1) @staticmethod - def run_cmd(cmd, args=[], quiet=False): + def run_cmd(cmd, args=[], quiet=False, cwd=None): if not quiet: Executor.print_cmd_line(cmd, args) try: - return subprocess.call([cmd] + args) + return subprocess.call([cmd] + args, cwd=cwd) except OSError as e: Executor.fail("[Failed - %s] %s" % (cmd, e.strerror)) @staticmethod def run_cmd_output(cmd, args=[], quiet=False): + if not quiet: + Executor.print_cmd_line(cmd, args) + try: + process = subprocess.Popen([cmd] + args, stdout=subprocess.PIPE) + output = process.communicate()[0] + + return output + except OSError as e: + Executor.fail("[Failed - %s] %s" % (cmd, e.strerror)) + + @staticmethod + def check_run_cmd_output(cmd, args=[], quiet=False): if not quiet: Executor.print_cmd_line(cmd, args) try: @@ -60,8 +90,8 @@ def run_cmd_output(cmd, args=[], quiet=False): Executor.fail("[Failed - %s] %s" % (cmd, e.strerror)) @staticmethod - def check_run_cmd(cmd, args=[], quiet=False): - retcode = Executor.run_cmd(cmd, args, quiet) + def check_run_cmd(cmd, args=[], quiet=False, cwd=None): + retcode = Executor.run_cmd(cmd, args, quiet, cwd) if retcode != 0: Executor.fail("[Failed - %d] %s" % (retcode, Executor.cmd_line(cmd, args))) diff --git a/tools/common_py/system/platform.py b/tools/common_py/system/sys_platform.py similarity index 77% rename from tools/common_py/system/platform.py rename to tools/common_py/system/sys_platform.py index 5f7c7f3d0e..e60d772b60 100644 --- a/tools/common_py/system/platform.py +++ b/tools/common_py/system/sys_platform.py @@ -13,11 +13,19 @@ # limitations under the License. import os - +import platform +import sys class Platform(object): def __init__(self): - _os, _, _, _, _arch = os.uname() + if sys.platform == "win32": + _os = "windows" + if platform.architecture()[0] == "64bit": + _arch = "x86_64" + else: + _arch = "i686" + else: + _os, _, _, _, _arch = os.uname() self._os = _os self._arch = _arch diff --git a/tools/iotjs-create-module.py b/tools/iotjs-create-module.py new file mode 100755 index 0000000000..020023d6d8 --- /dev/null +++ b/tools/iotjs-create-module.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python + +# 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. + +from __future__ import print_function + +import os +import re + +IOTJS_BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) +TEMPLATE_BASE_DIR = os.path.join(os.path.dirname(__file__), 'module_templates') +MODULE_NAME_RE = "^[a-z0-9][a-z0-9\._]*$" + +def load_templates(template_dir): + for root, dirs, files in os.walk(template_dir): + for fp in files: + yield os.path.relpath(os.path.join(root, fp), template_dir) + + +def replace_contents(input_file, module_name): + with open(input_file) as fp: + data = fp.read() + data = data.replace("$MODULE_NAME$", module_name) + data = data.replace("$IOTJS_PATH$", IOTJS_BASE_DIR) + + return data + +def create_module(output_dir, module_name, template_dir, template_files): + module_path = os.path.join(output_dir, module_name) + print("Creating module in {}".format(module_path)) + + if os.path.exists(module_path): + print("Module path ({}) already exists! Exiting".format(module_path)) + return False + + for file_name in template_files: + file_path = os.path.join(template_dir, file_name) + print("loading template file: {}".format(file_path)) + contents = replace_contents(file_path, module_name) + output_path = os.path.join(module_path, file_name) + + # create sub-dir if required + base_dir = os.path.dirname(output_path) + if not os.path.exists(base_dir): + os.mkdir(base_dir) + + with open(output_path, "w") as fp: + fp.write(contents) + + return True + +def valid_module_name(value): + if not re.match(MODULE_NAME_RE, value): + msg = "Invalid module name, should match regexp: %s" % MODULE_NAME_RE + raise argparse.ArgumentTypeError(msg) + return value + +if __name__ == "__main__": + import argparse + import sys + + desc = "Create an IoT.js external module using a template" + parser = argparse.ArgumentParser(description=desc) + parser.add_argument("module_name", metavar="", nargs=1, + type=valid_module_name, + help="name of the new module ((must be in lowercase " + + "and should match regexp: %s)" % MODULE_NAME_RE) + parser.add_argument("--path", default=".", + help="directory where the module will be created " + + "(default: %(default)s)") + parser.add_argument("--template", default="basic", + choices=["basic", "shared"], + help="type of the template which should be used " + "(default: %(default)s)") + args = parser.parse_args() + + + template_dir = os.path.join(TEMPLATE_BASE_DIR, + "%s_module_template" % args.template) + template_files = load_templates(template_dir) + created = create_module(args.path, + args.module_name[0], + template_dir, + template_files) + if created: + module_path = os.path.join(args.path, args.module_name[0]) + print("Module created in: {}".format(os.path.abspath(module_path))) diff --git a/tools/iotjs-generate-module.py b/tools/iotjs-generate-module.py new file mode 100755 index 0000000000..7ed2ddedf7 --- /dev/null +++ b/tools/iotjs-generate-module.py @@ -0,0 +1,224 @@ +#!/usr/bin/env python + +# Copyright 2019-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. + +import os +import sys + +from common_py import path +from common_py.system.filesystem import FileSystem as fs + +from module_generator.source_generator import CSourceGenerator, \ + CppSourceGenerator +from module_generator.clang_translation_unit_visitor import ClangTUVisitor + + +def generate_c_source(header, api_headers, dirname, args): + + visit_args = [] + if args.define: + visit_args += ['-D' + defs for defs in args.define] + if args.defines: + visit_args += ['-D' + defs for defs in args.defines.read().splitlines()] + if args.include: + visit_args += ['-I' + inc for inc in args.include] + if args.includes: + visit_args += ['-I' + inc for inc in args.includes.read().splitlines()] + + visitor = ClangTUVisitor(args.lang, header, api_headers, args.check_all, + visit_args, args.verbose) + visitor.visit() + + if args.check or args.check_all: + visitor.check(visitor) + + if args.lang == 'c': + generator = CSourceGenerator() + elif args.lang == 'c++': + generator = CppSourceGenerator() + + generated_source = [INCLUDE.format(HEADER=dirname + '_js_binding.h')] + + if 'macros' not in args.off: + generator.macros = visitor.macro_defs + + def visit_namespace(namespace): + generator.create_ns_obj() + if 'records' not in args.off: + for record in namespace.record_decls: + generated_source.append(generator.create_record(record)) + + if 'functions' not in args.off: + for function in namespace.function_decls: + generated_source.append(generator.create_ext_function(function)) + + if 'enums' not in args.off: + for decl in namespace.enum_constant_decls: + generator.enums += decl.enums + + if 'variables' not in args.off: + for var in namespace.var_decls: + generated_source.append(generator.create_getter_setter(var)) + + generator.create_init_function_body() + + for ns in namespace.namespaces: + generator.namespace.append(ns.name) + visit_namespace(ns) + generator.regist_ns_obj() + generator.namespace.pop() + + visit_namespace(visitor) + + generated_source.append(generator.create_init_function(dirname)) + + return ('\n').join(generated_source) + + +def generate_header(directory): + includes = [] + api_headers = [] + for root, dirs, files in os.walk(directory): + for file in files: + if file.endswith('.h'): + api_headers.append(os.path.abspath(os.path.join(root, file))) + includes.append('#include "' + + os.path.abspath(os.path.join(root, file)) + + '"') + + return ('\n').join(includes), api_headers + + +def search_for_lib(directory): + for root, dirs, files in os.walk(directory): + for file in files: + if file.startswith('lib') and file.endswith('.a'): + return (root, file) + + +def generate_module(args): + directory = args.directory + + if fs.isdir(directory): + # handle strings end with '/' + if directory[-1] == '/': + directory = directory[:-1] + + dirname = fs.basename(directory) + else: + sys.exit('Please give an existing directory.') + + if args.out_dir: + output_dir = args.out_dir + else: + output_dir = fs.join(fs.join(path.TOOLS_ROOT, 'module_generator'), + 'output') + + if not fs.isdir(output_dir): + os.mkdir(output_dir) + + output_dir = fs.join(output_dir, dirname + '_module') + + if not fs.isdir(output_dir): + os.mkdir(output_dir) + + src_dir = fs.join(output_dir, 'src') + + if not fs.isdir(src_dir): + os.mkdir(src_dir) + + header_file = fs.join(src_dir, dirname + '_js_binding.h') + header_text, api_headers = generate_header(directory) + + with open(header_file, 'w') as h: + h.write(header_text) + + c_file = generate_c_source(header_file, api_headers, dirname, args) + + extension = 'cpp' if args.lang == 'c++' else 'c' + with open(fs.join(src_dir, dirname + '_js_binding.' + extension), 'w') as c: + c.write(c_file) + + library = search_for_lib(directory) + + if not library: + print ('\033[93mWARNING: Cannot find library file. ' + + 'Only the binding layer source has generated.\033[00m') + return + + lib_root, lib_name = library + cmake_file = MODULE_CMAKE.format(NAME=dirname, LIBRARY=lib_name[3:-2]) + + with open(fs.join(output_dir, 'module.cmake'), 'w') as cmake: + cmake.write(cmake_file) + + fs.copyfile(fs.join(lib_root, lib_name), fs.join(output_dir, lib_name)) + + json_file = MODULES_JSON.format(NAME=dirname, CMAKE='module.cmake') + + if args.lang == 'c++': + cmake_lists = CMAKE_LISTS.format(NAME=dirname) + with open(fs.join(src_dir, 'CMakeLists.txt'), 'w') as cmake: + cmake.write(cmake_lists) + + with open(fs.join(output_dir, 'modules.json'), 'w') as json: + json.write(json_file) + + +if __name__ == '__main__': + import argparse + + parser = argparse.ArgumentParser() + parser.add_argument('directory', help='Root directory of the C/C++ API.') + + parser.add_argument('lang', choices=['c', 'c++'], + help='Specify the language of the API. (default: %(default)s)') + + parser.add_argument('--out-dir', help='Output directory for the module. ' + + '(default: tools/module_generator/output)') + + parser.add_argument('--off', choices=['functions', 'variables', 'enums', + 'macros', 'records'], + action='append', default=[], help='Turn off source generating.') + + parser.add_argument('--define', action='append', default=[], + help='Add macro definition.') + parser.add_argument('--defines', type=argparse.FileType('r'), + help='A file, which contains macro definitions.') + + parser.add_argument('--include', action='append', default=[], + help='Add path to include file.') + parser.add_argument('--includes', type=argparse.FileType('r'), + help='A file, which contains paths to include files.') + + parser.add_argument('--check', action='store_true', default=False, + help='Check the C API headers. Print the unsupported parts.') + + parser.add_argument('--check-all', action='store_true', default=False, + help='Check the C API headers.') + + parser.add_argument('-v' , '--verbose', action='store_true', default=False, + help='Print errors, detected by clang.') + + args = parser.parse_args() + + if args.lang == 'c': + from module_generator.c_source_templates import INCLUDE, MODULES_JSON, \ + MODULE_CMAKE + elif args.lang == 'c++': + from module_generator.cpp_source_templates import INCLUDE, \ + MODULES_JSON, MODULE_CMAKE, CMAKE_LISTS + + generate_module(args) diff --git a/tools/js2c.py b/tools/js2c.py index d4478f17ee..2bf9c84da5 100755 --- a/tools/js2c.py +++ b/tools/js2c.py @@ -18,6 +18,7 @@ # And this file also generates magic string list in src/iotjs_string_ext.inl.h # file to reduce JerryScript heap usage. +import os import re import subprocess import struct @@ -26,6 +27,13 @@ from common_py import path +def normalize_str(text): + if not isinstance(text, str): + return text.decode('utf-8') + + return text + + def regroup(l, n): return [l[i:i+n] for i in range(0, len(l), n)] @@ -47,39 +55,6 @@ def remove_whitespaces(code): return re.sub('\n+', '\n', re.sub('\n +', '\n', code)) -def force_str(string): - if not isinstance(string, str): - return string.decode('utf-8') - else: - return string - - -def parse_literals(code): - JERRY_SNAPSHOT_VERSION = 7 - - literals = set() - - header = struct.unpack('IIII', code[0:16]) - if header[0] != JERRY_SNAPSHOT_VERSION : - print ('Please check jerry snapshot version (Last confirmed: %d)' - % JERRY_SNAPSHOT_VERSION) - exit(1) - - code_ptr = header[1] + 8 - while code_ptr < len(code): - length = struct.unpack('H', code[code_ptr : code_ptr + 2])[0] - code_ptr = code_ptr + 2 - if length == 0: - continue - if length < 32: - item = struct.unpack('%ds' % length, - code[code_ptr : code_ptr + length]) - literals.add(force_str(item[0])) - code_ptr = code_ptr + length + (length % 2) - - return literals - - LICENSE = ''' /* Copyright 2015-present Samsung Electronics Co., Ltd. and other contributors * @@ -117,6 +92,25 @@ def parse_literals(code): MAGIC_STRINGS_HEADER = '#define JERRY_MAGIC_STRING_ITEMS \\\n' +MODULE_SNAPSHOT_VARIABLES_H = ''' +extern const char module_{NAME}[]; +extern const uint32_t module_{NAME}_idx; +''' + +MODULE_SNAPSHOT_VARIABLES_C = ''' +#define MODULE_{NAME}_IDX ({IDX}) +const char module_{NAME}[] = "{NAME}"; +const uint32_t module_{NAME}_idx = MODULE_{NAME}_IDX; +''' + +NATIVE_SNAPSHOT_STRUCT_H = ''' +typedef struct { + const char* name; + const uint32_t idx; +} iotjs_js_module_t; + +extern const iotjs_js_module_t js_modules[]; +''' MODULE_VARIABLES_H = ''' extern const char {NAME}_n[]; @@ -138,13 +132,13 @@ def parse_literals(code): const char* name; const void* code; const size_t length; -} iotjs_js_module; +} iotjs_js_module_t; -extern const iotjs_js_module natives[]; +extern const iotjs_js_module_t js_modules[]; ''' NATIVE_STRUCT_C = ''' -const iotjs_js_module natives[] = {{ +const iotjs_js_module_t js_modules[] = {{ {MODULES} }}; ''' @@ -168,44 +162,64 @@ def format_code(code, indent): return "\n".join(lines) -def get_snapshot_contents(module_name, snapshot_generator): +def merge_snapshots(snapshot_infos, snapshot_tool): + output_path = fs.join(path.SRC_ROOT, 'js','merged.modules') + cmd = [snapshot_tool, "merge", "-o", output_path] + cmd.extend([item['path'] for item in snapshot_infos]) + + ret = subprocess.call(cmd) + + if ret != 0: + msg = "Failed to merge %s: - %d" % (snapshot_infos, ret) + print("%s%s%s" % ("\033[1;31m", msg, "\033[0m")) + exit(1) + + for item in snapshot_infos: + fs.remove(item['path']) + + with open(output_path, 'rb') as snapshot: + code = snapshot.read() + + fs.remove(output_path) + return code + + +def get_snapshot_contents(js_path, snapshot_tool, literals=None): """ Convert the given module with the snapshot generator and return the resulting bytes. """ - js_path = fs.join(path.SRC_ROOT, 'js', module_name + '.js') wrapped_path = js_path + ".wrapped" snapshot_path = js_path + ".snapshot" + module_name = os.path.splitext(os.path.basename(js_path))[0] with open(wrapped_path, 'w') as fwrapped, open(js_path, "r") as fmodule: if module_name != "iotjs": - fwrapped.write("(function(exports, require, module) {\n") + fwrapped.write("(function(exports, require, module, native) {\n") fwrapped.write(fmodule.read()) if module_name != "iotjs": fwrapped.write("});\n") - - ret = subprocess.call([snapshot_generator, - "--save-snapshot-for-eval", - snapshot_path, - wrapped_path]) - if ret != 0: - msg = "Failed to dump %s: - %d" % (js_path, ret) - print("%s%s%s" % ("\033[1;31m", msg, "\033[0m")) - exit(1) - - with open(snapshot_path, 'rb') as snapshot: - code = snapshot.read() + cmd = [snapshot_tool, "generate", "-o", snapshot_path] + if literals: + cmd.extend(["--static", "--load-literals-list-format", literals]) + ret = subprocess.call(cmd + [wrapped_path]) fs.remove(wrapped_path) - fs.remove(snapshot_path) + if ret != 0: + if literals == None: + msg = "Failed to dump %s: - %d" % (js_path, ret) + print("%s%s%s" % ("\033[1;31m", msg, "\033[0m")) + exit(1) + else: + print("Unable to create static snapshot from '%s'. Falling back " + "to normal snapshot." % js_path) - return code + return snapshot_path -def get_js_contents(name, is_debug_mode=False): +def get_js_contents(js_path, is_debug_mode=False): """ Read the contents of the given js module. """ - js_path = fs.join(path.SRC_ROOT, 'js', name + '.js') with open(js_path, "r") as f: code = f.read() @@ -216,12 +230,56 @@ def get_js_contents(name, is_debug_mode=False): return code -def js2c(buildtype, no_snapshot, js_modules, js_dumper, verbose=False): - is_debug_mode = buildtype == "debug" +def get_literals_from_snapshots(snapshot_tool, snapshot_list): + literals_path = fs.join(path.SRC_ROOT, 'js', 'literals.list') + cmd = [snapshot_tool, "litdump", "-o", literals_path] + cmd.extend(snapshot_list) + + ret = subprocess.call(cmd) + + if ret != 0: + msg = "Failed to dump the literals: - %d" % ret + print("%s%s%s" % ("\033[1;31m", msg, "\033[0m")) + exit(1) + + return literals_path + + +def read_literals(literals_path): + literals_set = set() + with open(literals_path, 'rb') as fin: + num = '' + while True: + c = normalize_str(fin.read(1)) + if not c: + break + elif c == ' ': + text = normalize_str(fin.read(int(num))) + literals_set.add(text) + num = '' + else: + num += c + + return literals_set + + +def write_literals_to_file(literals_set, literals_path): + sorted_lit = sorted(literals_set, key=lambda x: (len(x), x)) + with open(literals_path, 'wb') as flit: + for lit in sorted_lit: + entry = "%d %s\n" % (len(lit), lit) + flit.write(entry.encode('utf-8')) + + +def js2c(options, js_modules): + is_debug_mode = (options.buildtype == "debug") + snapshot_tool = options.snapshot_tool + no_snapshot = (snapshot_tool == None) + verbose = options.verbose magic_string_set = set() str_const_regex = re.compile('^#define IOTJS_MAGIC_STRING_\w+\s+"(\w+)"$') - with open(fs.join(path.SRC_ROOT, 'iotjs_magic_strings.h'), 'r') as fin_h: + with open(fs.join(path.SRC_ROOT, 'iotjs_magic_strings.in'), 'r') as fin_h: for line in fin_h: result = str_const_regex.search(line) if result: @@ -236,33 +294,83 @@ def js2c(buildtype, no_snapshot, js_modules, js_dumper, verbose=False): fout_c.write(LICENSE) fout_c.write(HEADER2) - for name in sorted(js_modules): + snapshot_infos = [] + js_module_names = [] + if no_snapshot: + for idx, module in enumerate(sorted(js_modules)): + [name, js_path] = module.split('=', 1) + js_module_names.append(name) + if verbose: + print('Processing module: %s' % name) + + code = get_js_contents(js_path, is_debug_mode) + code_string = format_code(code, 1) + + fout_h.write(MODULE_VARIABLES_H.format(NAME=name)) + fout_c.write(MODULE_VARIABLES_C.format(NAME=name, + NAME_UPPER=name.upper(), + SIZE=len(code), + CODE=code_string)) + modules_struct = [ + ' {{ {0}_n, {0}_s, SIZE_{1} }},'.format(name, name.upper()) + for name in sorted(js_module_names) + ] + modules_struct.append(' { NULL, NULL, 0 }') + native_struct_h = NATIVE_STRUCT_H + else: + # Generate snapshot files from JS files + for idx, module in enumerate(sorted(js_modules)): + [name, js_path] = module.split('=', 1) + js_module_names.append(name) + if verbose: + print('Processing (1st phase) module: %s' % name) + code_path = get_snapshot_contents(js_path, snapshot_tool) + info = {'name': name, 'path': code_path, 'idx': idx} + snapshot_infos.append(info) + + # Get the literal list from the snapshots if verbose: - print('Processing module: %s' % name) - - if no_snapshot: - code = get_js_contents(name, is_debug_mode) - else: - code = get_snapshot_contents(name, js_dumper) - magic_string_set |= parse_literals(code) - + print('Creating literal list file for static snapshot ' + 'creation') + literals_path = get_literals_from_snapshots(snapshot_tool, + [info['path'] for info in snapshot_infos]) + magic_string_set |= read_literals(literals_path) + # Update the literals list file + write_literals_to_file(magic_string_set, literals_path) + + # Generate static-snapshots if possible + for idx, module in enumerate(sorted(js_modules)): + [name, js_path] = module.split('=', 1) + if verbose: + print('Processing (2nd phase) module: %s' % name) + + get_snapshot_contents(js_path, snapshot_tool, literals_path) + + fout_h.write(MODULE_SNAPSHOT_VARIABLES_H.format(NAME=name)) + fout_c.write(MODULE_SNAPSHOT_VARIABLES_C.format(NAME=name, + IDX=idx)) + fs.remove(literals_path) + + # Merge the snapshot files + code = merge_snapshots(snapshot_infos, snapshot_tool) code_string = format_code(code, 1) + name = 'iotjs_js_modules' fout_h.write(MODULE_VARIABLES_H.format(NAME=name)) fout_c.write(MODULE_VARIABLES_C.format(NAME=name, NAME_UPPER=name.upper(), SIZE=len(code), CODE=code_string)) - - fout_h.write(NATIVE_STRUCT_H) + modules_struct = [ + ' {{ module_{0}, MODULE_{0}_IDX }},'.format(info['name']) + for info in snapshot_infos + ] + modules_struct.append(' { NULL, 0 }') + native_struct_h = NATIVE_SNAPSHOT_STRUCT_H + + fout_h.write(native_struct_h) fout_h.write(FOOTER1) - modules_struct = [ - ' {{ {0}_n, {0}_s, SIZE_{1} }},'.format(name, name.upper()) - for name in sorted(js_modules) - ] - modules_struct.append(' { NULL, NULL, 0 }') - fout_c.write(NATIVE_STRUCT_C.format(MODULES="\n".join(modules_struct))) fout_c.write(EMPTY_LINE) @@ -275,6 +383,7 @@ def js2c(buildtype, no_snapshot, js_modules, js_dumper, verbose=False): sorted_strings = sorted(magic_string_set, key=lambda x: (len(x), x)) for idx, magic_string in enumerate(sorted_strings): magic_text = repr(magic_string)[1:-1] + magic_text = magic_text.replace('"', '\\"') fout_magic_str.write(' MAGICSTR_EX_DEF(MAGIC_STR_%d, "%s") \\\n' % (idx, magic_text)) @@ -290,22 +399,21 @@ def js2c(buildtype, no_snapshot, js_modules, js_dumper, verbose=False): choices=['debug', 'release'], default='debug', help='Specify the build type: %(choices)s (default: %(default)s)') parser.add_argument('--modules', required=True, - help='List of JS modules to process. Format: ,,...') - parser.add_argument('--snapshot-generator', default=None, - help='Executable to use for generating snapshots from the JS files. ' + help='List of JS files to process. Format: ' + '=,=,...') + parser.add_argument('--snapshot-tool', default=None, + help='Executable to use for generating snapshots and merging them ' + '(ex.: the JerryScript snapshot tool). ' 'If not specified the JS files will be directly processed.') parser.add_argument('-v', '--verbose', default=False, help='Enable verbose output.') options = parser.parse_args() - if not options.snapshot_generator: + if not options.snapshot_tool: print('Converting JS modules to C arrays (no snapshot)') - no_snapshot = True else: - print('Using "%s" as snapshot generator' % options.snapshot_generator) - no_snapshot = False + print('Using "%s" as snapshot tool' % options.snapshot_tool) - modules = options.modules.replace(',', ' ').split() - js2c(options.buildtype, no_snapshot, modules, options.snapshot_generator, - options.verbose) + modules = options.modules.split(',') + js2c(options, modules) diff --git a/tools/measure_coverage.sh b/tools/measure_coverage.sh index 395465d2c8..a8f9276a93 100755 --- a/tools/measure_coverage.sh +++ b/tools/measure_coverage.sh @@ -37,44 +37,61 @@ print_npm_dep() echo "" } -check_architecture() +print_usage() { - architecture=$(uname -m) - case $architecture in - i386|i686|x86_32) - ;; - *) - echo "Error: You can measure test coverage only on x86 32-bit." - exit 1 - esac + echo "Measure JavaScript and C coverage and create a html report" + echo "out of the results" + echo "" + echo "Usage: measure_coverage.sh [ARGUMENTS]" + echo "" + echo "Optional Arguments:" + echo " --node-modules-dir Specifies the node_module directory, where" + echo " the nodejs dependencies are installed." + echo "" + echo " --target-board Specifies the target board, where the" + echo " coverage measurement will happen." + echo " Possible values: rpi2" + echo "" + echo "The created html reports can be found in the 'coverage' directory," + echo "which will be created in the IoT.js project source dir. The C and" + echo "JavaScript coverage reports are in the 'c' and 'js' subdirectories" + echo "respectively. The reports can be viewed by opening the 'index.html'" + echo "file in a web browser of your choice." + echo "" + echo "Running the script will require some additional dependencies." + echo "" + print_dep + print_nvm_dep + print_npm_dep + exit 0 } -if [ "$#" -gt "0" ] && ( [ "$1" == "-h" ] || [ "$1" == "--help" ] ); then - echo "Measure JavaScript and C coverage and create a html report" - echo "out of the results" - echo "" - echo "Usage: $0 [NODE_MODULES_DIR]" - echo "" - echo "Optional Arguments:" - echo " NODE_MODULES_DIR Specifies the node_module directory, where" - echo " the nodejs dependencies are installed." - echo "" - echo "The created html reports can be found in the 'coverage' directory," - echo "which will be created in the IoT.js project source dir. The C and" - echo "JavaScript coverage reports are in the 'c' and 'js' subdirectories" - echo "respectively. The reports can be viewed by opening the 'index.html'" - echo "file in a web browser of your choice." - echo "" - echo "Running the script will require some additional dependencies." - echo "" - print_dep - print_nvm_dep - print_npm_dep - exit 0 -fi +fail_with_msg() +{ + echo "$1" + exit 1 +} -# Don't run this script on x86_64 architecture, only on x86_32 -check_architecture +# Parse the given arguments. +while [[ $# -gt 0 ]] +do + key="$1" + + case $key in + --node-modules-dir) + node_modules_dir="$2" + shift + ;; + --target-board) + target_board="$2" + shift + ;; + *) + print_usage + ;; + esac + shift +done tools_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" iotjs_root=$(readlink -f "$tools_dir/..") @@ -91,7 +108,12 @@ fi . ~/.profile # Istanbul and babel require node version > 4.0. -nvm install 6.11.0 +nvm ls 4.0.0 >> /dev/null 2>&1 +if [ "$?" -ne "0" ]; then + nvm install 4.0 +else + nvm use 4.0 +fi dpkg -l lcov >> /dev/null 2>&1 && \ dpkg -l gcc-multilib >> /dev/null 2>&1 @@ -103,11 +125,11 @@ fi modules_dir=$(readlink -f "$(npm bin)/..") -if [ "$#" -gt "0" ]; then - path=$(readlink -f $1) +if [ -v node_modules_dir ]; +then + path=$(readlink -f $node_modules_dir) if [ ! -d "$path" ] || [ $(basename "$path") != "node_modules" ]; then - echo "'$1' is not a node_modules directory" - exit 1 + fail_with_msg "'$node_modules_dir' is not a node_modules directory" fi test -e $path/.bin/nyc && \ @@ -142,11 +164,36 @@ mv src/cover_js src/js # Build iot.js # We need to use the system allocator to have enough memory, for now this can # only be done with a 32-bit build -tools/build.py --jerry-cmake-param="-DFEATURE_SYSTEM_ALLOCATOR=ON" \ - --target-arch=x86 --compile-flag="-coverage" --no-snapshot --no-check-test +common_build_opts="--jerry-cmake-param=-DJERRY_SYSTEM_ALLOCATOR=ON +--compile-flag=-coverage +--no-snapshot" + +if ! [ -v target_board ]; +then + tools/build.py $common_build_opts --target-arch=x86 \ + --profile=test/profiles/host-linux.profile + + if [ $? -ne 0 ]; then + fail_with_msg "x86 build failed." + fi + + build_path=${PWD}/build/i686-linux/debug +elif [ $target_board = "rpi2" ]; +then + tools/build.py $common_build_opts --target-arch=arm --target-board=rpi2 \ + --profile=test/profiles/rpi2-linux.profile + + if [ $? -ne 0 ]; then + fail_with_msg "RPi2 build failed." + fi + + build_path=${PWD}/build/arm-linux/debug +else + fail_with_msg "Not supported target-board: $target_board" +fi -# Run tests -build/i686-linux/debug/bin/iotjs tools/check_test.js -- output-coverage=yes +# Run the appropriate testrunner. +python tools/testrunner.py ${build_path}/bin/iotjs --quiet --coverage # Revert to original module files rm -rf src/js @@ -162,7 +209,7 @@ rm -rf coverage/js mv coverage/lcov-report coverage/js # Generate c coverage report -lcov -t "c_coverage" -o ".c-coverage.info" -c -d build/i686-linux/debug/ +lcov -t "c_coverage" -o ".c-coverage.info" -c -d $build_path lcov --remove ".c-coverage.info" 'iotjs/deps/*' -o ".c-coverage.info" genhtml -o coverage/c .c-coverage.info rm .c-coverage.info diff --git a/tools/module_analyzer.py b/tools/module_analyzer.py deleted file mode 100644 index 1b1b72b2e8..0000000000 --- a/tools/module_analyzer.py +++ /dev/null @@ -1,225 +0,0 @@ -#!/usr/bin/env python - -# 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. - -from __future__ import print_function - -import re - -from common_py.system.filesystem import FileSystem as fs -from common_py.system.executor import Executor as ex -from common_py.system.platform import Platform -from common_py import path - -platform = Platform() - -def resolve_modules(options): - """ Resolve include/exclude module lists based on command line arguments - and build config. - """ - # Load the modules which are always enabled and the include/exclude sets - build_modules_always = set(options.config['module']['always']) - build_modules_includes = set(options.config['module']['include']) - build_modules_excludes = set(options.config['module']['exclude']['all']) - - if options.target_os: - system_os = options.target_os - if system_os == 'tizen': - system_os = 'linux' - build_modules_excludes |= set( - options.config['module']['exclude'][system_os]) - - # Build options has higher priority than defaults - build_modules_excludes -= options.iotjs_include_module - - # By default the target included modules are: - # - always module set from the build config - # - modules specified by the command line argument - include_modules = set() | build_modules_always - include_modules |= options.iotjs_include_module - - if not options.iotjs_minimal_profile: - # Add the include set from the build config to - # the target include modules set - include_modules |= build_modules_includes - - # Check if there are any modules which are not allowed to be excluded - impossible_to_exclude = options.iotjs_exclude_module & build_modules_always - if impossible_to_exclude: - ex.fail('Cannot exclude modules which are always enabled: %s' % - ', '.join(impossible_to_exclude)) - - # Finally build up the excluded module set: - # - use the command line exclude set - # - use the exclude set from the build config - exclude_modules = options.iotjs_exclude_module | build_modules_excludes - - # Remove the excluded modules from the included modules set - include_modules -= exclude_modules - - return include_modules, exclude_modules - - -def analyze_module_dependency(include_modules, exclude_modules): - analyze_queue = set(include_modules) # copy the set - analyze_queue.add('iotjs') - - js_modules = { 'native' } - native_modules = { 'process' } - while analyze_queue: - item = analyze_queue.pop() - js_modules.add(item) - js_module_path = fs.join(path.PROJECT_ROOT, - 'src', 'js', item + '.js') - if not fs.exists(js_module_path): - ex.fail('Cannot read file "%s"' % js_module_path) - with open(js_module_path) as module: - content = module.read() - - # Pretend to ignore comments in JavaScript - re_js_comments = "\/\/.*|\/\*.*\*\/"; - content = re.sub(re_js_comments, "", content) - - # Get all required modules - re_js_module = 'require\([\'\"](.*?)[\'\"]\)' - required_modules = set(re.findall(re_js_module, content)) - # Check if there is any required modules in the exclude set - problem_modules = required_modules & exclude_modules - if problem_modules: - ex.fail('Cannot exclude module(s) "%s" since "%s" requires them' % - (', '.join(problem_modules), item)) - - # Add all modules to analytze queue which are not yet analyzed - analyze_queue |= required_modules - js_modules - - # Get all native modules - re_native_module = 'process.binding\(process.binding.(.*?)\)' - native_modules |= set(re.findall(re_native_module, content)) - - js_modules.remove('native') - - modules = {'js': sorted(js_modules), 'native': sorted(native_modules)} - - return modules - - -def _normalize_module_set(argument): - """ Split up argument via commas and make sure they have a valid value """ - return set([module.strip() for module in argument.split(',') - if module.strip()]) - - -def _load_options(argv): - try: - basestring - except: - # in Python 3.x there is no basestring just str - basestring = str - - # Specify the allowed options for the script - opts = [ - {'name': 'iotjs-minimal-profile', - 'args': dict(action='store_true', default=False, - help='Build IoT.js with minimal profile') - }, - {'name': 'iotjs-include-module', - 'args': dict(action='store', default=set(), - type=_normalize_module_set, - help='Specify iotjs modules which should be included ' - '(format: module_1,module_2,...)') - }, - {'name': 'iotjs-exclude-module', - 'args': dict(action='store', default=set(), - type=_normalize_module_set, - help='Specify iotjs modules which should be excluded ' - '(format: module_1,module_2,...)') - }, - {'name': 'target-os', - 'args': dict(choices=['linux', 'darwin', 'nuttx', 'tizen', 'tizenrt'], - default=platform.os, type=str.lower, - help='Specify the target os: %(choices)s (default: %(default)s)') - }, - {'name': 'mode', - 'args': dict(choices=['verbose', 'cmake-dump'], - default='verbose', - help='Execution mode of the script. Choices: %(choices)s ' - '(default: %(default)s)' - ), - }, - ] - allowed_options = [opt['name'] for opt in opts] - - arg_config = list(filter(lambda x: x.startswith('--config='), argv)) - config_path = path.BUILD_CONFIG_PATH - - if arg_config: - config_path = arg_config[-1].split('=', 1)[1] - - # Read config file and apply it to argv. - with open(config_path, 'rb') as f: - config = json.loads(f.read().decode('ascii')) - - loaded_argv = [] - for opt_key, opt_value in config['build_option'].items(): - if opt_key not in allowed_options: - continue # ignore any option that is not for us - - if isinstance(opt_value, basestring) and opt_value: - loaded_argv.append('--%s=%s' % (opt_key, opt_value)) - elif isinstance(opt_value, bool): - if opt_value: - loaded_argv.append('--%s' % opt_key) - elif isinstance(opt_value, int): - loaded_argv.append('--%s=%s' % (opt_key, opt_value)) - elif isinstance(opt_value, list): - for val in opt_value: - loaded_argv.append('--%s=%s' % (opt_key, val)) - - # Apply command line argument to argv. - loaded_argv.extend([arg for arg in argv[1:] - if not arg.startswith('--config=')]) - - # Build up the argument parser and process the args - parser = argparse.ArgumentParser() - - for opt in opts: - parser.add_argument('--%s' % opt['name'], **opt['args']) - - options = parser.parse_args(loaded_argv) - options.config = config - - return options - - -def _main(): - options = _load_options(sys.argv) - - includes, excludes = resolve_modules(options) - modules = analyze_module_dependency(includes, excludes) - - if options.mode == 'cmake-dump': - print('IOTJS_JS_MODULES=' + ';'.join(modules['js'])) - print('IOTJS_NATIVE_MODULES=' + ';'.join(modules['native'])) - else: - print('Selected js modules: %s' % ', '.join(modules['js'])) - print('Selected native modules: %s' % ', '.join(modules['native'])) - - -if __name__ == '__main__': - import argparse - import json - import sys - - _main() diff --git a/tools/module_generator/__init__.py b/tools/module_generator/__init__.py new file mode 100644 index 0000000000..ef65bee5bb --- /dev/null +++ b/tools/module_generator/__init__.py @@ -0,0 +1 @@ +# Required for Python to search this directory for module files diff --git a/tools/module_generator/c_source_templates.py b/tools/module_generator/c_source_templates.py new file mode 100644 index 0000000000..18dcdab6af --- /dev/null +++ b/tools/module_generator/c_source_templates.py @@ -0,0 +1,735 @@ +#!/usr/bin/env python + +# Copyright 2019-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. + + +# Templates for create/set a C variable + +# one length String to char +JS_TO_CHAR = ''' + // create a character value from a jerry_value_t + {TYPE} {NAME}; + jerry_string_to_char_buffer ({JVAL}, (jerry_char_t*)(&{NAME}), 1); +''' + +# Set a char variable +JS_SET_CHAR = ''' + // set the value of {NAME} + jerry_string_to_char_buffer ({JVAL}, (jerry_char_t*)(&{NAME}), 1); +''' + +# Number to int/float/enum +JS_TO_NUMBER = ''' + // create an integer / floating point number from a jerry_value_t + {TYPE} {NAME} = ({TYPE})jerry_get_number_value ({JVAL}); +''' + +# Set an int/float/enum variable +JS_SET_NUMBER = ''' + // set the value of {NAME} + {NAME} = jerry_get_number_value ({JVAL}); +''' + +# Boolean to _Bool +JS_TO_BOOL = ''' + // create a _Bool value from a jerry_value_t + {TYPE} {NAME} = jerry_value_to_boolean ({JVAL}); +''' + +# Set a _Bool variable +JS_SET_BOOL = ''' + // set the value of {NAME} + {NAME} = jerry_value_to_boolean ({JVAL}); +''' + +# String to char[] +JS_TO_STRING = ''' + // create an array of characters from a jerry_value_t + {TYPE} * {NAME} = NULL; + if (jerry_value_is_string ({JVAL})) + {{ + jerry_size_t {NAME}_size = jerry_get_string_size ({JVAL}); + {NAME} = malloc ({NAME}_size + 1); + if({NAME} == NULL) + {{ + return jerry_create_error (JERRY_ERROR_COMMON, (const jerry_char_t*)"Fail to allocate memory."); + }} + jerry_string_to_char_buffer ({JVAL}, (jerry_char_t*){NAME}, {NAME}_size); + {NAME}[{NAME}_size] = '\\0'; + }} +''' + +JS_FREE_STRING = ''' + // TODO: if you won't use {NAME} pointer, uncomment the lines below + //if (jerry_value_is_string ({JVAL})) + // free ({NAME}); +''' + +# Set a char* variable +JS_SET_CHAR_PTR = ''' + // set the value of {NAME} + jerry_size_t size = jerry_get_string_size ({JVAL}); + if ({NAME} == NULL) + {{ + {NAME} = ({TYPE}*) malloc (size + 1); + }} + jerry_string_to_char_buffer ({JVAL}, (jerry_char_t*){NAME}, size); + {NAME}[size] = '\\0'; +''' + +# Set a char[] variable +JS_SET_CHAR_ARR = ''' + // set the value of {NAME} + jerry_string_to_char_buffer ({JVAL}, (jerry_char_t*){NAME}, {SIZE}); + {NAME}[{SIZE}] = '\\0'; +''' + +# TypedArray to number pointer +JS_TO_TYPEDARRAY = ''' + // create a pointer to number from a jerry_value_t + {TYPE} * {NAME} = NULL; + jerry_length_t {NAME}_byteLength = 0; + jerry_length_t {NAME}_byteOffset = 0; + jerry_value_t {NAME}_buffer; + if (jerry_value_is_typedarray ({JVAL})) + {{ + {NAME}_buffer = jerry_get_typedarray_buffer ({JVAL}, &{NAME}_byteOffset, &{NAME}_byteLength); + {NAME} = ({TYPE}*) malloc ({NAME}_byteLength); + if({NAME} == NULL) + {{ + jerry_release_value ({NAME}_buffer); + return jerry_create_error (JERRY_ERROR_COMMON, (const jerry_char_t*)"Fail to allocate memory."); + }} + jerry_arraybuffer_read ({NAME}_buffer, {NAME}_byteOffset, (uint8_t*){NAME}, {NAME}_byteLength); + }} +''' + +JS_FREE_BUFFER = ''' + jerry_release_value ({NAME}_buffer); + // TODO: if you won't use {NAME} pointer, uncomment the line below + //free ({NAME}); +''' + +JS_FREE_WRITE_BUFFER = ''' + // write the values back into an arraybuffer from a pointer + if (jerry_value_is_typedarray ({JVAL})) + {{ + jerry_arraybuffer_write ({NAME}_buffer, {NAME}_byteOffset, (uint8_t*){NAME}, {NAME}_byteLength); + jerry_release_value ({NAME}_buffer); + // TODO: if you won't use {NAME} pointer, uncomment the line below + //free ({NAME}); + }} +''' + +# Set a number pointer +JS_SET_TYPEDARRAY = ''' + // set the value of {NAME} + jerry_length_t byteLength = 0; + jerry_length_t byteOffset = 0; + jerry_value_t buffer; + if (jerry_value_is_typedarray ({JVAL})) + {{ + buffer = jerry_get_typedarray_buffer ({JVAL}, &byteOffset, &byteLength); + if ({NAME} == NULL) + {{ + {NAME} = ({TYPE}*) malloc (byteLength); + }} + jerry_arraybuffer_read (buffer, byteOffset, (uint8_t*){NAME}, byteLength); + jerry_release_value (buffer); + }} + else + {{ + {NAME} = NULL; + }} +''' + +# Object to struct/union +JS_TO_RECORD = ''' + // create a record from a jerry_value_t + void* {NAME}_void_ptr; + const jerry_object_native_info_t* {NAME}_type_ptr; + bool {NAME}_has_ptr = jerry_get_object_native_pointer({JVAL}, &{NAME}_void_ptr, &{NAME}_type_ptr); + + if (!{NAME}_has_ptr || + ({NAME}_type_ptr != &{RECORD}_type_info && {NAME}_type_ptr != &{RECORD}_type_info_static)) {{ + char const *msg = "Failed to get native {TYPE} pointer"; + return jerry_create_error(JERRY_ERROR_TYPE, (const jerry_char_t *)msg); + }} + + {TYPE} {NAME} = *(({TYPE}*){NAME}_void_ptr); +''' + +# Set a struct/union +JS_SET_RECORD = ''' + // set the value of {NAME} + void* {RECORD}_void_ptr; + const jerry_object_native_info_t* {RECORD}_type_ptr; + bool {RECORD}_has_ptr = jerry_get_object_native_pointer({JVAL}, &{RECORD}_void_ptr, &{RECORD}_type_ptr); + + if (!{RECORD}_has_ptr || + ({RECORD}_type_ptr != &{RECORD}_type_info && {RECORD}_type_ptr != &{RECORD}_type_info_static)) {{ + char const *msg = "Failed to get native {RECORD} pointer"; + return jerry_create_error(JERRY_ERROR_TYPE, (const jerry_char_t *)msg); + }} + + {NAME} = *(({TYPE}*){RECORD}_void_ptr); +''' + +# Set a const struct/union +JS_SET_CONST_RECORD = ''' + // set the value of {NAME} + void* {RECORD}_void_ptr; + const jerry_object_native_info_t* {RECORD}_type_ptr; + bool {RECORD}_has_ptr = jerry_get_object_native_pointer({JVAL}, &{RECORD}_void_ptr, &{RECORD}_type_ptr); + + if (!{RECORD}_has_ptr || + ({RECORD}_type_ptr != &{RECORD}_type_info && {RECORD}_type_ptr != &{RECORD}_type_info_static)) {{ + char const *msg = "Failed to get native {RECORD} pointer"; + return jerry_create_error(JERRY_ERROR_TYPE, (const jerry_char_t *)msg); + }} + + memcpy(&{NAME}, {RECORD}_void_ptr, sizeof({TYPE})); +''' + +# Object to struct/union pointer +JS_TO_RECORD_PTR = ''' + // create a record pointer from a jerry_value_t + void* {NAME}_void_ptr; + const jerry_object_native_info_t* {NAME}_type_ptr; + bool {NAME}_has_ptr = jerry_get_object_native_pointer({JVAL}, &{NAME}_void_ptr, &{NAME}_type_ptr); + + if (!{NAME}_has_ptr || + ({NAME}_type_ptr != &{RECORD}_type_info && {NAME}_type_ptr != &{RECORD}_type_info_static)) {{ + char const *msg = "Failed to get native {TYPE} pointer"; + return jerry_create_error(JERRY_ERROR_TYPE, (const jerry_char_t *)msg); + }} + + {TYPE} * {NAME} = ({TYPE}*){NAME}_void_ptr; +''' + +# Function to C function +JS_TO_FUNCTION = ''' + // create a function pointer from a jerry_value_t + {TYPE} (*{NAME})({PARAMS}) = NULL; + if (jerry_value_is_function({JVAL})) + {{ + {FUNC}_{NAME}_js = {JVAL}; + {NAME} = {FUNC}_{NAME}; + }} +''' + +JS_CB_FUNCTION = ''' +// native callback function +jerry_value_t {FUNC}_{NAME}_js; +{RET_TYPE} {FUNC}_{NAME} ({PARAMS}) +{{ + jerry_value_t args[{LENGTH}]; + {CREATE_VAL} + jerry_value_t this_val = jerry_create_undefined(); + jerry_value_t result = jerry_call_function({FUNC}_{NAME}_js, this_val, args, {LENGTH}); + {RESULT} + jerry_release_value(result); + jerry_release_value(this_val); + + for (int i = 0; i < {LENGTH}; i++) + {{ + jerry_release_value(args[i]); + }} + return {RET}; +}} +''' + +# Unsupported C type +JS_TO_UNSUPPORTED = ''' + // TODO: Define the right value of the variable. + {TYPE} {NAME}; +''' + + +# Templates for create a jerry_value_t variable + +# Create Undefined/Bool/Number/Object +JS_CREATE_VAL = ''' + jerry_value_t {NAME} = jerry_create_{TYPE} ({FROM}); +''' + +# Create one length String +JS_CREATE_CHAR = ''' + jerry_value_t {NAME} = jerry_create_string_sz ((jerry_char_t*)(&{FROM}), 1); +''' + +# Create String +JS_CREATE_STRING = ''' + jerry_value_t {NAME}; + if ({FROM} != NULL) + {{ + {NAME} = jerry_create_string ((jerry_char_t*){FROM}); + }} + else + {{ + {NAME} = jerry_create_null (); + }} +''' + +# Create TypedArray or Null +JS_CREATE_TYPEDARRAY = ''' + // create a typedarray or null from a pointer + jerry_value_t {NAME}; + if ({FROM} != NULL) + {{ + jerry_length_t {NAME}_byteLength = sizeof({TYPE}); + jerry_value_t {NAME}_buffer = jerry_create_arraybuffer ({NAME}_byteLength); + jerry_arraybuffer_write ({NAME}_buffer, 0, (uint8_t*){FROM}, {NAME}_byteLength); + {NAME} = jerry_create_typedarray_for_arraybuffer_sz (JERRY_TYPEDARRAY_{ARRAY_TYPE}, {NAME}_buffer, 0, 1); + jerry_release_value ({NAME}_buffer); + }} + else + {{ + {NAME} = jerry_create_null (); + }} +''' + +TYPEDARRAYS = { + 'signed char': 'INT8', + 'unsigned char': 'UINT8', + 'short': 'INT16', + 'unsigned short': 'UINT16', + 'int': 'INT32', + 'unsigned int': 'UINT32', + 'long': 'INT32', + 'unsigned long': 'UINT32', + 'long long': 'INT32', + 'unsigned long long': 'UINT32', + 'float': 'FLOAT32', + 'double': 'FLOAT64', + 'long double': 'FLOAT64' +} + +# Create Object +JS_CREATE_OBJECT = ''' + // create object from record + {TYPE}* {RECORD}_native_ptr = ({TYPE}*)calloc(1, sizeof({TYPE})); + *{RECORD}_native_ptr = {FROM}; + jerry_value_t {NAME} = {RECORD}_js_creator({RECORD}_native_ptr); + jerry_set_object_native_pointer({NAME}, {RECORD}_native_ptr, &{RECORD}_type_info); +''' + +# Create Object +JS_CREATE_CONST_OBJECT = ''' + // create object from record + {TYPE}* {RECORD}_native_ptr = ({TYPE}*)calloc(1, sizeof({TYPE})); + memcpy({RECORD}_native_ptr, &{FROM}, sizeof({TYPE})); + jerry_value_t {NAME} = {RECORD}_js_creator({RECORD}_native_ptr); + jerry_set_object_native_pointer({NAME}, {RECORD}_native_ptr, &{RECORD}_type_info); +''' + +# Unsupported C type +JS_CREATE_UNSUPPORTED = ''' + // TODO: Create a valid jerry_value_t from '{FROM}'. + jerry_value_t {NAME} = jerry_create_undefined (); +''' + + +# Templates for record types + +# Record destructor +JS_RECORD_DESTRUCTOR = ''' +void {RECORD}_js_destructor(void* ptr) {{ + free(({TYPE}*)ptr); +}} + +static const jerry_object_native_info_t {RECORD}_type_info = {{ + .free_cb = {RECORD}_js_destructor +}}; + +static const jerry_object_native_info_t {RECORD}_type_info_static = {{ + .free_cb = NULL +}}; +''' + +# Member getter/setter template +JS_RECORD_MEMBER = ''' +// external function for getter/setter of record member +jerry_value_t {RECORD}_{NAME} (const jerry_value_t function_obj, + const jerry_value_t this_val, + const jerry_value_t args_p[], + const jerry_length_t args_cnt) +{{ + void* void_ptr; + const jerry_object_native_info_t* type_ptr; + bool has_ptr = jerry_get_object_native_pointer(this_val, &void_ptr, &type_ptr); + + if (!has_ptr || + (type_ptr != &{RECORD}_type_info && type_ptr != &{RECORD}_type_info_static)) {{ + char const *msg = "Failed to get native {RECORD} pointer"; + return jerry_create_error(JERRY_ERROR_TYPE, (const jerry_char_t *)msg); + }} + + {TYPE}* native_ptr = ({TYPE}*)(void_ptr); +{BODY} + return ret_val; +}} +''' + +JS_RECORD_GETTER = ''' +// external function for record getter +jerry_value_t {RECORD}{NAME}_getter (const jerry_value_t function_obj, + const jerry_value_t this_val, + const jerry_value_t args_p[], + const jerry_length_t args_cnt) +{{ + jerry_value_t {NAME}_name = jerry_create_string((const jerry_char_t *) "_{NAME}"); + jerry_value_t {NAME}_value = jerry_get_property(this_val, {NAME}_name); + jerry_release_value({NAME}_name); + return {NAME}_value; +}} +''' + +# Record constructor +JS_RECORD_CONSTRUCTOR = ''' +// external function for record constructor +jerry_value_t {RECORD}_js_constructor (const jerry_value_t function_obj, + const jerry_value_t this_val, + const jerry_value_t args_p[], + const jerry_length_t args_cnt) +{{ + (void) {RECORD}_type_info_static; + {TYPE}* native_ptr = ({TYPE}*)calloc(1, sizeof({TYPE})); + if (args_cnt == 0) + {{ + jerry_value_t ret_val = {RECORD}_js_creator(native_ptr); + jerry_set_object_native_pointer(ret_val, native_ptr, &{RECORD}_type_info); + return ret_val; + }} + + if (args_cnt != 1 || !jerry_value_is_object (args_p[0])) + {{ + char const *msg = "Wrong argument for {RECORD}(), expected an object."; + return jerry_create_error (JERRY_ERROR_TYPE, (const jerry_char_t*)msg); + }} +{BODY} + jerry_value_t ret_val = {RECORD}_js_creator(native_ptr); + jerry_set_object_native_pointer(ret_val, native_ptr, &{RECORD}_type_info); + return ret_val; +}} +''' + +JS_RECORD_RETURN = ''' + jerry_value_t ret_val = {RECORD}_js_creator(native_ptr); + jerry_set_object_native_pointer(ret_val, native_ptr, &{RECORD}_type_info); + return ret_val; +''' + +JS_GET_PROP_STRUCT = ''' + {TYPE} {NAME}{INIT}; + jerry_value_t {NAME}_name = jerry_create_string((const jerry_char_t *) "{NAME}"); + jerry_value_t {NAME}_value = jerry_get_property(args_p[0], {NAME}_name); + jerry_release_value({NAME}_name); + if (!jerry_value_is_undefined({NAME}_value)) + {{ +{GET_VAL} + }} + jerry_release_value({NAME}_value); +''' + +JS_GET_PROP_UNION = ''' + jerry_value_t {NAME}_name = jerry_create_string((const jerry_char_t *) "{NAME}"); + jerry_value_t {NAME}_value = jerry_get_property(args_p[0], {NAME}_name); + jerry_release_value({NAME}_name); + if (!jerry_value_is_undefined({NAME}_value)) + {{ + {TYPE} {NAME}{INIT}; +{GET_VAL} + jerry_release_value({NAME}_value); +{RET} + }} + jerry_release_value({NAME}_value); +''' + +JS_INIT_MEMBERS = ''' + *native_ptr = ({TYPE}){{{MEMBERS}}}; +''' + +JS_INIT_MEMBERS_CONST = ''' + {TYPE} native = {{{MEMBERS}}}; + memcpy(native_ptr, &native, sizeof({TYPE})); +''' + +JS_RECORD_CREATOR = ''' +jerry_value_t {RECORD}_js_creator ({TYPE}* native_ptr) +{{ + jerry_value_t js_obj = jerry_create_object(); + {REGIST} + return js_obj; +}} +''' + +JS_REGIST_MEMBER = ''' + // set record's member as a property to the object + jerry_property_descriptor_t {RECORD}_{NAME}_prop_desc; + jerry_init_property_descriptor_fields (&{RECORD}_{NAME}_prop_desc); + {RECORD}_{NAME}_prop_desc.is_get_defined = true; + {RECORD}_{NAME}_prop_desc.is_set_defined = true; + {RECORD}_{NAME}_prop_desc.getter = jerry_create_external_function ({RECORD}_{NAME}_getter); + {RECORD}_{NAME}_prop_desc.setter = jerry_create_external_function ({RECORD}_{NAME}_setter); + jerry_value_t {RECORD}_{NAME}_prop_name = jerry_create_string ((const jerry_char_t *)"{NAME}"); + jerry_value_t {RECORD}_{NAME}_return_value = jerry_define_own_property (js_obj, {RECORD}_{NAME}_prop_name, &{RECORD}_{NAME}_prop_desc); + jerry_release_value ({RECORD}_{NAME}_return_value); + jerry_release_value ({RECORD}_{NAME}_prop_name); + jerry_free_property_descriptor_fields (&{RECORD}_{NAME}_prop_desc); +''' + + +JS_REGIST_RECORD = ''' + // set record as a property to the object + jerry_value_t {NAME}_js = {RECORD}_js_creator (&{REF}); + jerry_set_object_native_pointer({NAME}_js, &{REF}, &{RECORD}_type_info_static); + jerry_property_descriptor_t {NAME}_js_prop_desc; + jerry_init_property_descriptor_fields (&{NAME}_js_prop_desc); + {NAME}_js_prop_desc.is_value_defined = true; + {NAME}_js_prop_desc.value = {NAME}_js; + jerry_value_t {NAME}_js_prop_name = jerry_create_string ((const jerry_char_t *)"_{NAME}"); + jerry_value_t {NAME}_js_return_value = jerry_define_own_property ({OBJECT}, {NAME}_js_prop_name, &{NAME}_js_prop_desc); + jerry_release_value ({NAME}_js_return_value); + jerry_release_value ({NAME}_js_prop_name); + jerry_free_property_descriptor_fields (&{NAME}_js_prop_desc); +''' + +JS_REGIST_CONST_MEMBER = ''' + // set a constant member as a property to the object + jerry_property_descriptor_t {NAME}_prop_desc; + jerry_init_property_descriptor_fields (&{NAME}_prop_desc); + {NAME}_prop_desc.is_value_defined = true; + {NAME}_prop_desc.value = {NAME}_js; + jerry_value_t {NAME}_prop_name = jerry_create_string ((const jerry_char_t *)"{NAME}"); + jerry_value_t {NAME}_return_value = jerry_define_own_property (js_obj, {NAME}_prop_name, &{NAME}_prop_desc); + jerry_release_value ({NAME}_return_value); + jerry_release_value ({NAME}_prop_name); + jerry_free_property_descriptor_fields (&{NAME}_prop_desc); +''' + +JS_REGIST_CONST_RECORD = ''' + // set a constant record as a property to the object + jerry_property_descriptor_t {NAME}_prop_desc; + jerry_init_property_descriptor_fields (&{NAME}_prop_desc); + {NAME}_prop_desc.is_get_defined = true; + {NAME}_prop_desc.getter = jerry_create_external_function ({NAME}_getter); + jerry_value_t {NAME}_prop_name = jerry_create_string ((const jerry_char_t *)"{VALUE}"); + jerry_value_t {NAME}_return_value = jerry_define_own_property ({OBJECT}, {NAME}_prop_name, &{NAME}_prop_desc); + jerry_release_value ({NAME}_return_value); + jerry_release_value ({NAME}_prop_name); + jerry_free_property_descriptor_fields (&{NAME}_prop_desc); +''' + +JS_REGIST_ARR_MEMBER = ''' + // set a numeric array member as a property to the object + jerry_value_t {NAME}_buffer = jerry_create_arraybuffer_external (sizeof({TYPE}) * {SIZE}, (uint8_t*)native_ptr->{NAME}, NULL); + jerry_value_t {NAME}_typedarray = jerry_create_typedarray_for_arraybuffer_sz (JERRY_TYPEDARRAY_{ARRAY_TYPE}, {NAME}_buffer, 0, {SIZE}); + jerry_property_descriptor_t {NAME}_prop_desc; + jerry_init_property_descriptor_fields (&{NAME}_prop_desc); + {NAME}_prop_desc.is_value_defined = true; + {NAME}_prop_desc.value = {NAME}_typedarray; + jerry_value_t {NAME}_prop_name = jerry_create_string ((const jerry_char_t *)"{NAME}"); + jerry_value_t {NAME}_return_value = jerry_define_own_property (js_obj, {NAME}_prop_name, &{NAME}_prop_desc); + jerry_release_value ({NAME}_return_value); + jerry_release_value ({NAME}_prop_name); + jerry_release_value ({NAME}_buffer); + jerry_free_property_descriptor_fields (&{NAME}_prop_desc); +''' + + +# Template for a jerry_external_handler_t type function + +JS_EXT_FUNC = ''' +// external function for API functions or for getters / setters +jerry_value_t {NAME} (const jerry_value_t function_obj, + const jerry_value_t this_val, + const jerry_value_t args_p[], + const jerry_length_t args_cnt) +{{ +{BODY} + return ret_val; +}} +''' + + +# Template for check the count of the external function's arguments + +JS_CHECK_ARG_COUNT = ''' + // check the count of the external function's arguments + if (args_cnt != {COUNT}) + {{ + char const *msg = "Wrong argument count for {FUNC}(), expected {COUNT}."; + return jerry_create_error (JERRY_ERROR_TYPE, (const jerry_char_t*)msg); + }} +''' + + +# Templates for check the type of a jerry_value_t variable + +JS_CHECK_TYPE = ''' + // check the type of a jerry_value_t variable + if (!jerry_value_is_{TYPE} ({JVAL})) + {{ + char const *msg = "Wrong argument type for {FUNC}(), expected {TYPE}."; + return jerry_create_error (JERRY_ERROR_TYPE, (const jerry_char_t*)msg); + }} +''' + +JS_CHECK_POINTER = ''' + // check the type of a jerry_value_t variable + if (!jerry_value_is_{TYPE} ({JVAL}) && !jerry_value_is_null ({JVAL})) + {{ + char const *msg = "Wrong argument type for {FUNC}(), expected {TYPE} or null."; + return jerry_create_error (JERRY_ERROR_TYPE, (const jerry_char_t*)msg); + }} +''' + + +# Templates for the module initialization function + +INIT_FUNC = ''' +// init function for the module +jerry_value_t Init_{NAME}() +{{ +{BODY} + return object; +}} +''' + +INIT_REGIST_FUNC = ''' + // set an external function as a property to the module object + jerry_value_t {NAME}_name = jerry_create_string ((const jerry_char_t*)"{FUNC}"); + jerry_value_t {NAME}_func = jerry_create_external_function ({NAME}_handler); + jerry_value_t {NAME}_ret = jerry_set_property ({OBJECT}, {NAME}_name, {NAME}_func); + jerry_release_value ({NAME}_name); + jerry_release_value ({NAME}_func); + jerry_release_value ({NAME}_ret); +''' + +INIT_REGIST_RECORD = ''' + // set a constructor as a property to the module object + jerry_value_t {NAME}_name = jerry_create_string ((const jerry_char_t*)"{RECORD}"); + jerry_value_t {NAME}_func = jerry_create_external_function ({NAME}_js_constructor); + jerry_value_t {NAME}_ret = jerry_set_property ({OBJECT}, {NAME}_name, {NAME}_func); + jerry_release_value ({NAME}_name); + jerry_release_value ({NAME}_func); + jerry_release_value ({NAME}_ret); +''' + +INIT_REGIST_ENUM = ''' + // set an enum constant as a property to the module object + jerry_property_descriptor_t {NAME}_prop_desc; + jerry_init_property_descriptor_fields (&{NAME}_prop_desc); + {NAME}_prop_desc.is_value_defined = true; + {NAME}_prop_desc.value = jerry_create_number ({REF}); + jerry_value_t {NAME}_name = jerry_create_string ((const jerry_char_t *)"{ENUM}"); + jerry_value_t {NAME}_ret = jerry_define_own_property ({OBJECT}, {NAME}_name, &{NAME}_prop_desc); + jerry_release_value ({NAME}_ret); + jerry_release_value ({NAME}_name); + jerry_free_property_descriptor_fields (&{NAME}_prop_desc); +''' + +INIT_REGIST_VALUE = ''' + // set a global variable as a property to the module object + jerry_property_descriptor_t {NAME}_prop_desc; + jerry_init_property_descriptor_fields (&{NAME}_prop_desc); + {NAME}_prop_desc.is_get_defined = true; + {NAME}_prop_desc.is_set_defined = true; + {NAME}_prop_desc.getter = jerry_create_external_function ({NAME}_getter); + {NAME}_prop_desc.setter = jerry_create_external_function ({NAME}_setter); + jerry_value_t {NAME}_prop_name = jerry_create_string ((const jerry_char_t *)"{VALUE}"); + jerry_value_t {NAME}_return_value = jerry_define_own_property ({OBJECT}, {NAME}_prop_name, &{NAME}_prop_desc); + jerry_release_value ({NAME}_return_value); + jerry_release_value ({NAME}_prop_name); + jerry_free_property_descriptor_fields (&{NAME}_prop_desc); +''' + +INIT_REGIST_CONST = ''' + // set a global constant or a macro as a property to the module object + jerry_property_descriptor_t {NAME}_prop_desc; + jerry_init_property_descriptor_fields (&{NAME}_prop_desc); + {NAME}_prop_desc.is_value_defined = true; + {NAME}_prop_desc.value = {NAME}_js; + jerry_value_t {NAME}_prop_name = jerry_create_string ((const jerry_char_t *)"{VALUE}"); + jerry_value_t {NAME}_return_value = jerry_define_own_property ({OBJECT}, {NAME}_prop_name, &{NAME}_prop_desc); + jerry_release_value ({NAME}_return_value); + jerry_release_value ({NAME}_prop_name); + jerry_free_property_descriptor_fields (&{NAME}_prop_desc); +''' + +INIT_REGIST_NUM_ARR = ''' + // set a global numeric array as a property to the module object + jerry_value_t {NAME}_buffer = jerry_create_arraybuffer_external (sizeof({TYPE}) * {SIZE}, (uint8_t*){REF}, NULL); + jerry_value_t {NAME}_typedarray = jerry_create_typedarray_for_arraybuffer_sz (JERRY_TYPEDARRAY_{ARRAY_TYPE}, {NAME}_buffer, 0, {SIZE}); + jerry_property_descriptor_t {NAME}_prop_desc; + jerry_init_property_descriptor_fields (&{NAME}_prop_desc); + {NAME}_prop_desc.is_value_defined = true; + {NAME}_prop_desc.value = {NAME}_typedarray; + jerry_value_t {NAME}_prop_name = jerry_create_string ((const jerry_char_t *)"{ARR}"); + jerry_value_t {NAME}_return_value = jerry_define_own_property ({OBJECT}, {NAME}_prop_name, &{NAME}_prop_desc); + jerry_release_value ({NAME}_return_value); + jerry_release_value ({NAME}_prop_name); + jerry_release_value ({NAME}_buffer); + jerry_free_property_descriptor_fields (&{NAME}_prop_desc); +''' + +INIT_CREATE_OBJECT = ''' + jerry_value_t {NAME}object = jerry_create_object(); +''' + +INIT_REGIST_OBJECT = ''' + // set a namespace as a property to another namespace object + jerry_property_descriptor_t {NAME}_prop_desc; + jerry_init_property_descriptor_fields (&{NAME}_prop_desc); + {NAME}_prop_desc.is_value_defined = true; + {NAME}_prop_desc.value = {NAME}object; + jerry_value_t {NAME}_prop_name = jerry_create_string ((const jerry_char_t *)"{REF}"); + jerry_value_t {NAME}_return_value = jerry_define_own_property ({OBJECT}, {NAME}_prop_name, &{NAME}_prop_desc); + jerry_release_value ({NAME}_return_value); + jerry_release_value ({NAME}_prop_name); + jerry_free_property_descriptor_fields (&{NAME}_prop_desc); +''' + + +# Template for include the right headers + +INCLUDE = ''' +#include +#include +#include "jerryscript.h" +#include "{HEADER}" +''' + + +# Templates for modules.json and module.cmake + +MODULES_JSON = ''' +{{ + "modules": {{ + "{NAME}_module": {{ + "native_files": ["src/{NAME}_js_binding.c"], + "init": "Init_{NAME}", + "cmakefile": "{CMAKE}" + }} + }} +}} +''' + +MODULE_CMAKE = ''' +set(MODULE_NAME "{NAME}_module") +link_directories(${{MODULE_DIR}}) +list(APPEND MODULE_LIBS {LIBRARY}) +''' diff --git a/tools/module_generator/clang_translation_unit_visitor.py b/tools/module_generator/clang_translation_unit_visitor.py new file mode 100755 index 0000000000..9eeead48ca --- /dev/null +++ b/tools/module_generator/clang_translation_unit_visitor.py @@ -0,0 +1,841 @@ +#!/usr/bin/env python + +# Copyright 2019-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. + +from clang.cindex import Index, conf, CursorKind, TypeKind, AccessSpecifier + +# This class is a wrapper for the TypeKind and Type classes. +class ClangASTNodeType: + char_type_kinds = [ + TypeKind.CHAR_U, + TypeKind.CHAR16, + TypeKind.CHAR32, + TypeKind.CHAR_S, + TypeKind.WCHAR + ] + + number_type_kinds = [ + TypeKind.UCHAR, + TypeKind.SCHAR, + TypeKind.USHORT, + TypeKind.UINT, + TypeKind.ULONG, + TypeKind.ULONGLONG, + TypeKind.UINT128, + TypeKind.SHORT, + TypeKind.INT, + TypeKind.LONG, + TypeKind.LONGLONG, + TypeKind.INT128, + TypeKind.FLOAT, + TypeKind.DOUBLE, + TypeKind.LONGDOUBLE + ] + + def __init__(self, clang_type): + # We are only interested in the underlying canonical types. + self._canonical_type = clang_type.get_canonical() + self._type_name = clang_type.spelling.replace('const ', '') + + @property + def name(self): + return self._type_name + + @property + def canonical_name(self): + return self._canonical_type.spelling + + def is_bool(self): + return self._canonical_type.kind == TypeKind.BOOL + + def is_char(self): + return self._canonical_type.kind in ClangASTNodeType.char_type_kinds + + def is_number(self): + return self._canonical_type.kind in ClangASTNodeType.number_type_kinds + + def is_enum(self): + return self._canonical_type.kind == TypeKind.ENUM + + def is_void(self): + return self._canonical_type.kind == TypeKind.VOID + + def is_pointer(self): + return (self._canonical_type.kind == TypeKind.POINTER or + self._canonical_type.kind == TypeKind.CONSTANTARRAY or + self._canonical_type.kind == TypeKind.INCOMPLETEARRAY) + + def is_array(self): + return (self._canonical_type.kind == TypeKind.CONSTANTARRAY or + self._canonical_type.kind == TypeKind.INCOMPLETEARRAY) + + def is_record(self): + return self._canonical_type.kind == TypeKind.RECORD + + def is_struct(self): + return (self._canonical_type.get_declaration().kind == + CursorKind.STRUCT_DECL) + + def is_union(self): + return (self._canonical_type.get_declaration().kind == + CursorKind.UNION_DECL) + + def is_function(self): + return (self._canonical_type.kind == TypeKind.FUNCTIONPROTO or + self._canonical_type.kind == TypeKind.FUNCTIONNOPROTO) + + def is_const(self): + return self._canonical_type.is_const_qualified() + + def get_array_type(self): + return ClangASTNodeType(self._canonical_type.get_array_element_type()) + + def get_array_size(self): + assert self.is_array() + return self._canonical_type.element_count + + def get_pointee_type(self): + if self.is_array(): + array_type = self._canonical_type.get_array_element_type() + return ClangASTNodeType(array_type) + if self.is_pointer(): + return ClangASTNodeType(self._canonical_type.get_pointee()) + + def get_declaration(self): + return ClangASTNode(self._canonical_type.get_declaration()) + + def get_as_record_decl(self): + assert (self.is_record()) + return ClangRecordDecl(self._canonical_type.get_declaration()) + + def has_const_member(self): + ret = False + decl = self._canonical_type.get_declaration() + for child in decl.get_children(): + if child.kind == CursorKind.FIELD_DECL: + if child.type.get_canonical().kind == TypeKind.RECORD: + ret = ClangASTNodeType(child.type).has_const_member() + if child.type.is_const_qualified(): + ret = True + return ret + + +# This class is a wrapper for the Cursor type. +class ClangASTNode: + def __init__(self, cursor): + self._cursor = cursor + self._type = ClangASTNodeType(cursor.type) + self._kind = cursor.kind + + @property + def name(self): + return self._cursor.spelling + + @property + def type(self): + return self._type + + @property + def kind(self): + return self._kind + + def get_as_record_decl(self): + assert (self.type.is_record()) + return ClangRecordDecl(self._cursor) + + def get_as_function(self): + return ClangFunctionDecl(self._cursor) + + +# This class represents enum declarations in libclang. +class ClangEnumDecl: + def __init__(self, cursor): + self._enum_constant_decls = [] + + for child in cursor.get_children(): + if child.kind == CursorKind.ENUM_CONSTANT_DECL: + self._enum_constant_decls.append(child.spelling) + + @property + def enums(self): + return self._enum_constant_decls + + +# This class represents function declarations in libclang. +class ClangFunctionDecl(ClangASTNode): + def __init__(self, cursor): + ClangASTNode.__init__(self, cursor) + + if cursor.type.get_canonical().kind == TypeKind.POINTER: + return_type = cursor.type.get_canonical().get_pointee().get_result() + else: + return_type = cursor.type.get_canonical().get_result() + + self._return_type = ClangASTNodeType(return_type) + + self._parm_decls = [] + if cursor.type.kind == TypeKind.TYPEDEF: + children = cursor.type.get_declaration().get_children() + else: + children = cursor.get_children() + + for arg in children: + if arg.kind == CursorKind.PARM_DECL: + arg = ClangASTNode(arg) + self._parm_decls.append(arg) + + @property + def return_type(self): + return self._return_type + + @property + def params(self): + return self._parm_decls + + +# This class represents macro definitions in libclang. +# TokenKinds: +# 'PUNCTUATION' = 0 +# 'KEYWORD' = 1 +# 'IDENTIFIER' = 2 +# 'LITERAL' = 3 +# 'COMMENT' = 4 +class ClangMacroDef(ClangASTNode): + def __init__(self, cursor): + ClangASTNode.__init__(self, cursor) + + self.tokens = [] + self.token_kinds = [] + for token in cursor.get_tokens(): + self.tokens.append(token.spelling) + self.token_kinds.append(token.kind.value) + + @property + def content(self): + return (' ').join(self.tokens[1:]) + + def is_char(self): + if (self.token_kinds == [2, 3] and # "#define CH 'a'" like macros + "'" in self.tokens[1]): # char literal + return True + return False + + def is_string(self): + if (self.token_kinds == [2, 3] and # '#define STR "abc"' like macros + '"' in self.tokens[1]): # string literal + return True + return False + + # macro contains only number literals and punctuations + def is_number(self): + if (self.content and + not [x for x in self.token_kinds[1:] if x in [1, 2, 4]] and + "'" not in self.content and '"' not in self.content): + return True + return False + + def is_valid(self): + return self.is_char() or self.is_string() or self.is_number() + + def is_function(self): + return conf.lib.clang_Cursor_isMacroFunctionLike(self._cursor) + + +class ClangRecordConstructor: + def __init__(self, cursor_list, is_constructor = True, func_list = []): + self._suffix = '' + if cursor_list: + self._cursor = cursor_list[0] + + self._parm_decls = {} + param_lists = [] + for i, cursor in enumerate(cursor_list): + arguments = list(cursor.get_arguments()) + param_lists.append(([ClangASTNode(a) for a in arguments], i)) + + # handle default arguments + for arg in reversed(arguments): + if '=' in [t.spelling for t in arg.get_tokens()]: + arguments = arguments[:-1] + param_lists.append(([ClangASTNode(a) for a in arguments], + i)) + + # Codes: + # String - 0 + # Number - 1 + # Boolean - 2 + # TypedArray - 3 + # Function - 4 + # Object - name of the object + # Other - 5 + coded_param_lists = [] + for param_list, _ in param_lists: + coded_params = [] + for param in param_list: + param_t = param.type + if (param_t.is_char() or + (param_t.is_pointer() and + param_t.get_pointee_type().is_char())): + coded_params.append(0) + elif param_t.is_number() or param_t.is_enum(): + coded_params.append(1) + elif param_t.is_bool(): + coded_params.append(2) + elif param_t.is_function(): + coded_params.append(4) + elif param_t.is_record(): + record = param_t.get_as_record_decl().ns_name + coded_params.append(record) + elif param_t.is_pointer(): + pointee_t = param_t.get_pointee_type() + if pointee_t.is_char(): + coded_params.append(0) + elif pointee_t.is_number(): + coded_params.append(3) + elif pointee_t.is_function(): + coded_params.append(4) + elif pointee_t.is_record(): + record = pointee_t.get_as_record_decl().ns_name + coded_params.append(record) + else: + coded_params.append(5) + else: + coded_params.append(5) + coded_param_lists.append(coded_params) + + # Remove lists from `param_lists`, + # which have the same JS types of parameters + j = 0 + same_types_params = [] + for i, coded_params in enumerate(coded_param_lists): + if coded_params in coded_param_lists[:i] + coded_param_lists[i+1:]: + same_types_params.append(param_lists.pop(j)) + j -= 1 + j += 1 + + for param_list, _ in param_lists: + if len(param_list) in self._parm_decls: + self._parm_decls[len(param_list)].append(param_list) + else: + self._parm_decls[len(param_list)] = [param_list] + + for j, (params, i) in enumerate(same_types_params): + if is_constructor: + f = ClangRecordConstructor([cursor_list[i]]) + else: + f = ClangRecordMethod(self._cursor.spelling, [cursor_list[i]]) + f._suffix = '_$' + str(j) + func_list.append(f) + func_name = cursor_list[i].spelling + print ('\033[93mWARN: The following overload of ' + func_name + + ' has been renamed to ' + func_name + f._suffix + + ' :\033[00m') + print ' '.join(t.spelling for t in cursor_list[i].get_tokens()) + + @property + def params(self): + return self._parm_decls + + @property + def suffix(self): + return self._suffix + + +class ClangRecordMethod(ClangRecordConstructor): + def __init__(self, name, cursor_list, func_list = []): + ClangRecordConstructor.__init__(self, cursor_list, False, func_list) + + self._method_name = name + return_type = cursor_list[0].type.get_canonical().get_result() + self._return_type = ClangASTNodeType(return_type) + + @property + def name(self): + return self._method_name + + @property + def return_type(self): + return self._return_type + + +# This class represents struct/union/class declarations in libclang. +class ClangRecordDecl(ClangASTNode): + def __init__(self, cursor): + ClangASTNode.__init__(self, cursor) + + self._field_decls = [] + self._has_constructor = True + self._has_default_constructor = True + self._has_copy_constructor = True + self._constructors = [] + if cursor.spelling: + self._name = cursor.spelling + else: + self._name = self.type.name.split('::')[-1] + + constructors = [] + methods = {} + for child in cursor.get_children(): + if child.access_specifier == AccessSpecifier.PUBLIC: + if child.kind == CursorKind.CONSTRUCTOR: + constructors.append(child) + if child.kind == CursorKind.FIELD_DECL: + self._field_decls.append(ClangASTNode(child)) + if child.kind == CursorKind.CXX_METHOD: + if child.spelling in methods: + methods[child.spelling].append(child) + else: + methods[child.spelling] = [child] + + if not constructors and self.type.has_const_member(): + self._has_constructor = False + self._has_default_constructor = False + self._has_copy_constructor = False + elif constructors: + constructor = ClangRecordConstructor(constructors, True, + self._constructors) + if constructor.params: + self._constructors.append(constructor) + self._methods = [] + for name, cursor_list in methods.items(): + method = ClangRecordMethod(name, cursor_list, self._methods) + if method.params: + self._methods.append(method) + + @property + def name(self): + return self._name + + @property + def ns_name(self): + return self.type.name.replace('::', '_') + + @property + def constructors(self): + return self._constructors + + def has_constructor(self): + return self._has_constructor + + def has_default_constructor(self): + return self._has_default_constructor + + def has_copy_constructor(self): + return self._has_copy_constructor + + @property + def field_decls(self): + return self._field_decls + + @property + def methods(self): + return self._methods + + +class ClangNamespace: + def __init__(self, name, cursor_list): + self.name = name + self.enum_constant_decls = [] + self.function_decls = [] + self.var_decls = [] + self.record_decls = [] + self.namespaces = [] + + cpp_funcs = {} + namespaces = {} + for cursor in cursor_list: + children = cursor.get_children() + for child in children: + if child.kind == CursorKind.ENUM_DECL: + self.enum_constant_decls.append(ClangEnumDecl(child)) + + elif child.kind == CursorKind.FUNCTION_DECL: + if child.spelling in cpp_funcs: + cpp_funcs[child.spelling].append(child) + else: + cpp_funcs[child.spelling] = [child] + + elif child.kind == CursorKind.VAR_DECL: + self.var_decls.append(ClangASTNode(child)) + + elif (child.kind == CursorKind.CLASS_DECL or + child.kind == CursorKind.STRUCT_DECL or + child.kind == CursorKind.UNION_DECL): + self.record_decls.append(ClangRecordDecl(child)) + + elif child.kind == CursorKind.NAMESPACE: + if child.spelling in namespaces: + namespaces[child.spelling].append(child) + else: + namespaces[child.spelling] = [child] + + for name, cursor_list in cpp_funcs.items(): + func = ClangRecordMethod(name, cursor_list, self.function_decls) + if func.params: + self.function_decls.append() + + for name, cursor_list in namespaces.items(): + self.namespaces.append(ClangNamespace(name, cursor_list)) + +# This class responsible for initializing and visiting +# the AST provided by libclang. +class ClangTUVisitor: + def __init__(self, lang, header, api_headers, check_all, args, verbose): + index = Index.create() + + self.is_cpp = True if lang == 'c++' else False + self.clang_args = ['-x', lang] + self.translation_unit = index.parse(header, args + self.clang_args, + options=1) + + if verbose: + for diag in self.translation_unit.diagnostics: + if diag.severity == 2: + msg = '\033[93mWARNING : ' + elif diag.severity == 3: + msg = '\033[91mERROR : ' + elif diag.severity == 4: + msg = '\033[91mFATAL : ' + msg += '{} at {} line {}, column {}\033[00m' + print (msg.format(diag.spelling, diag.location.file, + diag.location.line, diag.location.column)) + + self.api_headers = api_headers + self.check_all = check_all + self.enum_constant_decls = [] + self.function_decls = [] + self.var_decls = [] + self.macro_defs = [] + self.record_decls = [] + self.namespaces = [] + + def visit(self): + children = self.translation_unit.cursor.get_children() + + cpp_funcs = {} + namespaces = {} + for cursor in children: + if (cursor.location.file != None and + cursor.location.file.name in self.api_headers): + + if cursor.kind == CursorKind.ENUM_DECL: + self.enum_constant_decls.append(ClangEnumDecl(cursor)) + + elif cursor.kind == CursorKind.FUNCTION_DECL: + if self.is_cpp: + if cursor.spelling in cpp_funcs: + cpp_funcs[cursor.spelling].append(cursor) + else: + cpp_funcs[cursor.spelling] = [cursor] + else: + self.function_decls.append(ClangFunctionDecl(cursor)) + + elif cursor.kind == CursorKind.VAR_DECL: + self.var_decls.append(ClangASTNode(cursor)) + + elif cursor.kind == CursorKind.MACRO_DEFINITION: + self.macro_defs.append(ClangMacroDef(cursor)) + + elif (cursor.kind == CursorKind.CLASS_DECL or + cursor.kind == CursorKind.STRUCT_DECL or + cursor.kind == CursorKind.UNION_DECL): + self.record_decls.append(ClangRecordDecl(cursor)) + + elif cursor.kind == CursorKind.NAMESPACE: + if cursor.spelling in namespaces: + namespaces[cursor.spelling].append(cursor) + else: + namespaces[cursor.spelling] = [cursor] + + for name, cursor_list in cpp_funcs.items(): + func = ClangRecordMethod(name, cursor_list, self.function_decls) + if func.params: + self.function_decls.append(func) + + for name, cursor_list in namespaces.items(): + self.namespaces.append(ClangNamespace(name, cursor_list)) + + # Resolve other macros in macro definition + for first in self.macro_defs: + for second in self.macro_defs: + for i, token in enumerate(second.tokens): + if i and first.name == token: + second.tokens = (second.tokens[:i] + + first.tokens[1:] + + second.tokens[i+1:]) + second.token_kinds = (second.token_kinds[:i] + + first.token_kinds[1:] + + second.token_kinds[i+1:]) + + def ok(self, msg): + return '\033[92m{}\033[00m'.format(msg) + + def warn(self, msg): + return '\033[91m{}\033[00m'.format(msg) + + def check(self, namespace): + if namespace == self: + self.check_macros() + self.check_variables(namespace) + + for record in namespace.record_decls: + record_is_ok, record_msg = self.check_record(record) + if not record_is_ok: + print(record_msg) + print(str(record._cursor.location) + '\n') + elif self.check_all: + print(self.ok('Supported record: ' + record.name) + '\n') + + for func in namespace.function_decls: + if self.is_cpp: + param_msg = [] + param_is_ok = True + for _, param_lists in func.params.items(): + for p_list in param_lists: + is_ok, msg = self.check_parameters(p_list) + if not is_ok: + param_is_ok = False + p_types = ', '.join([p.type.name for p in p_list]) + warn = self.warn( + 'Unsupported overload: {}({})'.format(func.name, + p_types)) + param_msg.append(warn) + param_msg.append(msg) + param_msg = '\n'.join(param_msg) + else: + param_is_ok, param_msg = self.check_parameters(func.params) + + ret_is_ok, ret_msg = self.check_return_type(func.return_type) + if not (param_is_ok and ret_is_ok): + print(self.warn('Unsupported function: ' + func.name)) + if param_msg: + print(param_msg) + if ret_msg: + print(ret_msg) + print(str(func._cursor.location) + '\n') + elif self.check_all: + print(self.ok('Supported function: ' + func.name) + '\n') + + for ns in namespace.namespaces: + self.check(ns) + + def check_macros(self): + for macro in self.macro_defs: + if not macro.is_valid(): + print(self.warn('Unsupported macro: ' + macro.name)) + print(str(macro._cursor.location) + '\n') + elif self.check_all: + print(self.ok('Supported macro: ' + macro.name) + '\n') + + def check_variables(self, namespace): + for var in namespace.var_decls: + is_supported = False + msg = '' + if (var.type.is_char() or var.type.is_number() or + var.type.is_enum() or var.type.is_bool()): + is_supported = True + elif var.type.is_pointer(): + pointee = var.type.get_pointee_type() + if pointee.is_char() or pointee.is_number(): + is_supported = True + elif var.type.is_record(): + var_record = var.type.get_as_record_decl() + is_supported, msg = self.check_record(var_record) + + if not is_supported: + print(self.warn( + 'Unsupported variable: {} {}'.format(var.type.name, + var.name))) + if msg: + print(msg) + print(str(var._cursor.location) + '\n') + elif self.check_all: + print(self.ok( + 'Supported variable: {} {}'.format(var.type.name, + var.name)) + '\n') + + def check_record(self, record): + record_msg = '' + # Check fields + field_msg = [] + field_is_ok = True + for field in record.field_decls: + is_supported = False + msg = '' + if (field.type.is_char() or field.type.is_number() or + field.type.is_enum() or field.type.is_bool()): + is_supported = True + elif field.type.is_pointer(): + pointee = field.type.get_pointee_type() + if pointee.is_char() or pointee.is_number(): + is_supported = True + elif field.type.is_record(): + field_record = field.type.get_as_record_decl() + is_supported, msg = self.check_record(field_record) + + if not is_supported: + field_is_ok = False + warn = self.warn( + 'Unsupported field: {} {}'.format(field.type.name, + field.name)) + field_msg.append(warn) + if msg: + field_msg.append(msg) + + # Check constructor + constructor_msg = [] + constructor_is_ok = True + for _, param_lists in record.constructor.params.items(): + for param_list in param_lists: + param_is_ok, param_msg = self.check_parameters(param_list) + if not param_is_ok: + constructor_is_ok = False + p_types = ', '.join([p.type.name for p in param_list]) + warn = self.warn( + 'Unsupported constructor: {}({})'.format(record.name, + p_types)) + constructor_msg.append(warn) + constructor_msg.append(param_msg) + + # Check methods + method_msg = [] + method_is_ok = True + for method in record.methods: + for _, param_lists in method.params.items(): + for param_list in param_lists: + param_is_ok, param_msg = self.check_parameters(param_list) + if not param_is_ok: + method_is_ok = False + p_types = ', '.join([p.type.name for p in param_list]) + warn = self.warn( + 'Unsupported overload: {}({})'.format(method.name, + p_types)) + method_msg.append(warn) + method_msg.append(param_msg) + + ret_is_ok, ret_msg = self.check_return_type(method.return_type) + + if not ret_is_ok: + method_is_ok = False + method_msg.append(ret_msg) + + if not method_is_ok: + warn = self.warn('Unsupported method: ' + method.name) + method_msg.insert(0, warn) + + record_msg = ('\n'.join(field_msg) + '\n'.join(constructor_msg) + + '\n'.join(method_msg)) + record_is_ok = field_is_ok and constructor_is_ok and method_is_ok + + if not record_is_ok: + record_msg = (self.warn('Unsupported record: ' + record.name) + '\n' + + record_msg) + + return record_is_ok, record_msg + + def check_parameters(self, param_list): + param_msg = [] + param_is_ok = True + for param in param_list: + is_supported = False + msg = '' + if (param.type.is_char() or param.type.is_number() or + param.type.is_enum() or param.type.is_bool()): + is_supported = True + elif param.type.is_pointer(): + pointee = param.type.get_pointee_type() + if pointee.is_char() or pointee.is_number(): + is_supported = True + elif pointee.is_record(): + record = pointee.get_as_record_decl() + is_supported, msg = self.check_record(record) + elif pointee.is_function(): + is_supported = self.check_func_ptr(param.get_as_function()) + elif param.type.is_record(): + record = param.get_as_record_decl() + is_supported, msg = self.check_record(record) + elif param.type.is_function(): + is_supported = self.check_func_ptr(param.get_as_function()) + + if not is_supported: + param_is_ok = False + warn = self.warn( + 'Unsupported parameter: {} {}'.format(param.type.name, + param.name)) + param_msg.append(warn) + if msg: + param_msg.append(msg) + + return param_is_ok, '\n'.join(param_msg) + + def check_return_type(self, return_type): + msg = '' + return_type_is_ok = False + if (return_type.is_void() or return_type.is_char() or + return_type.is_number() or return_type.is_enum() or + return_type.is_bool()): + return_type_is_ok = True + elif return_type.is_pointer(): + pointee = return_type.get_pointee_type() + if pointee.is_char() or pointee.is_number(): + return_type_is_ok = True + elif return_type.is_record(): + record = return_type.get_as_record_decl() + return_type_is_ok, msg = self.check_record(record) + + if not return_type_is_ok: + warn = self.warn('Unsupported return type: ' + return_type.name) + if msg: + msg = warn + '\n' + msg + else: + msg = warn + + return return_type_is_ok, msg + + def check_func_ptr(self, function): + param_is_ok = True + for param in function.params: + is_supported = False + if (param.type.is_char() or param.type.is_number() or + param.type.is_enum() or param.type.is_bool()): + is_supported = True + elif param.type.is_pointer(): + pointee = param.type.get_pointee_type() + if pointee.is_char() or pointee.is_number(): + is_supported = True + elif param.type.is_record(): + record = param.get_as_record_decl() + is_supported, _ = self.check_record(record) + if not is_supported: + param_is_ok = False + break + + ret_type = function.return_type + ret_is_ok = False + if (ret_type.is_void() or ret_type.is_char() or ret_type.is_number() or + ret_type.is_enum() or ret_type.is_bool()): + ret_is_ok = True + elif ret_type.is_pointer(): + pointee = ret_type.get_pointee_type() + if pointee.is_char() or pointee.is_number(): + ret_is_ok = True + elif pointee.is_record(): + record = pointee.get_as_record_decl() + ret_is_ok, _ = self.check_record(record) + elif ret_type.is_record(): + record = ret_type.get_as_record_decl() + ret_is_ok, _ = self.check_record(record) + + return (param_is_ok and ret_is_ok) diff --git a/tools/module_generator/cpp_source_templates.py b/tools/module_generator/cpp_source_templates.py new file mode 100644 index 0000000000..85a5699c34 --- /dev/null +++ b/tools/module_generator/cpp_source_templates.py @@ -0,0 +1,390 @@ +#!/usr/bin/env python + +# Copyright 2019-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. + + +# Templates for create/set a C++ variable + +# String to char[] +JS_TO_STRING = ''' + // create an array of characters from a jerry_value_t + {TYPE} * {NAME} = NULL; + if (jerry_value_is_string ({JVAL})) + {{ + jerry_size_t {NAME}_size = jerry_get_string_size ({JVAL}); + {NAME} = new {TYPE}[{NAME}_size + 1]; + jerry_string_to_char_buffer ({JVAL}, (jerry_char_t*){NAME}, {NAME}_size); + {NAME}[{NAME}_size] = '\\0'; + }} +''' + +JS_FREE_STRING = ''' + // TODO: if you won't use {NAME} pointer, uncomment the line below + //if (jerry_value_is_string ({JVAL})) + // delete[] {NAME}; +''' + +# Set a char* variable +JS_SET_CHAR_PTR = ''' + // set the value of {NAME} + jerry_size_t size = jerry_get_string_size ({JVAL}); + if ({NAME} == NULL) + {{ + {NAME} = new {TYPE}[size + 1]; + }} + jerry_string_to_char_buffer ({JVAL}, (jerry_char_t*){NAME}, size); + {NAME}[size] = '\\0'; +''' + +# TypedArray to number pointer +JS_TO_TYPEDARRAY = ''' + // create a pointer to number from a jerry_value_t + {TYPE} * {NAME} = NULL; + jerry_length_t {NAME}_byteLength = 0; + jerry_length_t {NAME}_byteOffset = 0; + jerry_value_t {NAME}_buffer; + if (jerry_value_is_typedarray ({JVAL})) + {{ + {NAME}_buffer = jerry_get_typedarray_buffer ({JVAL}, &{NAME}_byteOffset, &{NAME}_byteLength); + {NAME} = new {TYPE}[{NAME}_byteLength / sizeof({TYPE})]; + jerry_arraybuffer_read ({NAME}_buffer, {NAME}_byteOffset, (uint8_t*){NAME}, {NAME}_byteLength); + }} +''' + +JS_FREE_WRITE_BUFFER = ''' + // write the values back into an arraybuffer from a pointer + if (jerry_value_is_typedarray ({JVAL})) + {{ + jerry_arraybuffer_write ({NAME}_buffer, {NAME}_byteOffset, (uint8_t*){NAME}, {NAME}_byteLength); + jerry_release_value ({NAME}_buffer); + // TODO: if you won't use {NAME} pointer, uncomment the line below + //delete[] {NAME}; + }} +''' + +# Set a number pointer +JS_SET_TYPEDARRAY = ''' + // set the value of {NAME} + jerry_length_t byteLength = 0; + jerry_length_t byteOffset = 0; + jerry_value_t buffer; + if (jerry_value_is_typedarray ({JVAL})) + {{ + buffer = jerry_get_typedarray_buffer ({JVAL}, &byteOffset, &byteLength); + if ({NAME} == NULL) + {{ + {NAME} = new {TYPE}[byteLength / sizeof({TYPE})]; + }} + jerry_arraybuffer_read (buffer, byteOffset, (uint8_t*){NAME}, byteLength); + jerry_release_value (buffer); + }} + else + {{ + {NAME} = NULL; + }} +''' + +# Return Object +JS_RETURN_OBJECT = ''' + // create object from record + jerry_value_t {NAME} = {RECORD}_js_creator({FROM}); + jerry_set_object_native_pointer({NAME}, {FROM}, &{RECORD}_type_info); +''' + +# Alloc record +JS_ALLOC_RECORD = ''' + {RECORD}* {NAME} = ({RECORD}*)calloc(1, sizeof({RECORD})); +''' + + +# Template for check js type + +JS_VALUE_IS = '''jerry_value_is_{TYPE} ({JVAL})''' + +JS_POINTER_IS = '''(jerry_value_is_{TYPE} ({JVAL}) || jerry_value_is_null ({JVAL}))''' + +JS_CHECK_RECORD = ''' +bool jerry_value_is_{RECORD} (jerry_value_t jval) +{{ + if (!jerry_value_is_object (jval)) + {{ + return false; + }} + + void* ptr; + const jerry_object_native_info_t* type_ptr; + bool has_ptr = jerry_get_object_native_pointer(jval, &ptr, &type_ptr); + + if (!has_ptr || + (type_ptr != &{RECORD}_type_info && type_ptr != &{RECORD}_type_info_static)) + {{ + return false; + }} + + return true; +}} +''' + + +# Templates for record types + +# Record destructor +JS_RECORD_DESTRUCTOR = ''' +void {RECORD}_js_destructor(void* ptr) {{ + delete ({TYPE}*)ptr; +}} + +static const jerry_object_native_info_t {RECORD}_type_info = {{ + .free_cb = {RECORD}_js_destructor +}}; + +static const jerry_object_native_info_t {RECORD}_type_info_static = {{ + .free_cb = NULL +}}; +''' + +# Record constructor +JS_RECORD_CONSTRUCTOR = ''' +// external function for record constructor +jerry_value_t {RECORD}{SUFF}_js_constructor (const jerry_value_t function_obj, + const jerry_value_t this_val, + const jerry_value_t args_p[], + const jerry_length_t args_cnt) +{{ + {TYPE}* native_ptr; + switch (args_cnt) {{ + {CASE} + default: {{ + char const *msg = "Wrong argument count for {RECORD} constructor."; + return jerry_create_error (JERRY_ERROR_TYPE, (const jerry_char_t*)msg); + }} + }} + + jerry_value_t ret_val = {RECORD}_js_creator(native_ptr); + jerry_set_object_native_pointer(ret_val, native_ptr, &{RECORD}_type_info); + return ret_val; +}} +''' + +JS_CONSTR_CALL = ''' + if ({CONDITION}) + {{ + {GET_VAL} + native_ptr = new {NAME}({PARAMS}); + {FREE} + break; + }} +''' + +JS_CONSTR_CASE_0 = ''' + case 0: {{ + native_ptr = new {NAME}(); + break; + }} +''' + +JS_CONSTR_CASE = ''' + case {NUM}: {{ +{CALLS} + char const *msg = "Wrong argument type for {NAME} constructor."; + return jerry_create_error (JERRY_ERROR_TYPE, (const jerry_char_t*)msg); + }} +''' + +JS_REGIST_METHOD = ''' + // set record method as a property to the object + jerry_value_t {NAME}_name = jerry_create_string ((const jerry_char_t*)"{NAME}"); + jerry_value_t {NAME}_func = jerry_create_external_function ({RECORD}_{NAME}_handler); + jerry_value_t {NAME}_ret = jerry_set_property (js_obj, {NAME}_name, {NAME}_func); + jerry_release_value ({NAME}_name); + jerry_release_value ({NAME}_func); + jerry_release_value ({NAME}_ret); +''' + +JS_REGIST_CONST_MEMBER = ''' + // set a constant record member as a property to the object + jerry_property_descriptor_t {RECORD}_{NAME}_prop_desc; + jerry_init_property_descriptor_fields (&{RECORD}_{NAME}_prop_desc); + {RECORD}_{NAME}_prop_desc.is_value_defined = true; + {RECORD}_{NAME}_prop_desc.value = {RECORD}_{NAME}_js; + jerry_value_t {RECORD}_{NAME}_prop_name = jerry_create_string ((const jerry_char_t *)"{NAME}"); + jerry_value_t {RECORD}_{NAME}_return_value = jerry_define_own_property (js_obj, {RECORD}_{NAME}_prop_name, &{RECORD}_{NAME}_prop_desc); + jerry_release_value ({RECORD}_{NAME}_return_value); + jerry_release_value ({RECORD}_{NAME}_prop_name); + jerry_free_property_descriptor_fields (&{RECORD}_{NAME}_prop_desc); +''' + +# Record method +JS_RECORD_METHOD = ''' +// external function for record method +jerry_value_t {RECORD}_{NAME}{SUFF}_handler (const jerry_value_t function_obj, + const jerry_value_t this_val, + const jerry_value_t args_p[], + const jerry_length_t args_cnt) +{{ + void* void_ptr; + const jerry_object_native_info_t* type_ptr; + bool has_ptr = jerry_get_object_native_pointer(this_val, &void_ptr, &type_ptr); + + if (!has_ptr || + (type_ptr != &{RECORD}_type_info && type_ptr != &{RECORD}_type_info_static)) {{ + char const *msg = "Failed to get native {RECORD} pointer"; + return jerry_create_error(JERRY_ERROR_TYPE, (const jerry_char_t *)msg); + }} + + {TYPE}* native_ptr = ({TYPE}*)(void_ptr); + + {RESULT} + switch (args_cnt) {{ +{CASE} + default: {{ + char const *msg = "Wrong argument count for {RECORD}.{NAME}()."; + return jerry_create_error (JERRY_ERROR_TYPE, (const jerry_char_t*)msg); + }} + }} + + {RET_VAL} + return ret_val; +}} +''' + +JS_METHOD_CALL = ''' + if ({CONDITION}) + {{ + {GET_VAL} + {RESULT}native_ptr->{NAME}({PARAMS}); + {FREE} + break; + }} +''' + +JS_METHOD_CASE_0 = ''' + case 0: {{ + {RESULT}native_ptr->{NAME}(); + break; + }} +''' + +JS_METHOD_CASE = ''' + case {NUM}: {{ +{CALLS} + char const *msg = "Wrong argument type for {RECORD}.{NAME}()."; + return jerry_create_error (JERRY_ERROR_TYPE, (const jerry_char_t*)msg); + }} +''' + + +# Templates for C++ functions + +# Function +JS_EXT_CPP_FUNC = ''' +// external function for API functions +jerry_value_t {NAME}{SUFF}_handler (const jerry_value_t function_obj, + const jerry_value_t this_val, + const jerry_value_t args_p[], + const jerry_length_t args_cnt) +{{ + {RESULT} + switch (args_cnt) {{ +{CASE} + default: {{ + char const *msg = "Wrong argument count for {NAME}()."; + return jerry_create_error (JERRY_ERROR_TYPE, (const jerry_char_t*)msg); + }} + }} + + {RET_VAL} + return ret_val; +}} +''' + +JS_FUNC_CALL = ''' + if ({CONDITION}) + {{ + {GET_VAL} + {RESULT}{NAME}({PARAMS}); + {FREE} + break; + }} +''' + +JS_FUNC_CASE_0 = ''' + case 0: {{ + {RESULT}{NAME}(); + break; + }} +''' + +JS_FUNC_CASE = ''' + case {NUM}: {{ +{CALLS} + char const *msg = "Wrong argument type for {NAME}()."; + return jerry_create_error (JERRY_ERROR_TYPE, (const jerry_char_t*)msg); + }} +''' + + +# Templates for the module initialization function + +INIT_FUNC = ''' +// init function for the module +extern "C" jerry_value_t Init_{NAME}() +{{ +{BODY} + return object; +}} +''' + + +# Template for include the right headers + +INCLUDE = ''' +#include +#include +#include "jerryscript.h" +#include "{HEADER}" +''' + + +# Templates for modules.json, module.cmake and CMakeLists.txt + +MODULES_JSON = ''' +{{ + "modules": {{ + "{NAME}_module": {{ + "native_files": [], + "init": "Init_{NAME}", + "cmakefile": "{CMAKE}" + }} + }} +}} +''' + +MODULE_CMAKE = ''' +set(MODULE_NAME "{NAME}_module") +add_subdirectory(${{MODULE_DIR}}/src/ ${{MODULE_BINARY_DIR}}/${{MODULE_NAME}}) +link_directories(${{MODULE_DIR}}) +list(APPEND MODULE_LIBS {NAME}_binding {LIBRARY} stdc++) +''' + +CMAKE_LISTS = ''' +project({NAME} CXX) + +add_library({NAME}_binding STATIC + {NAME}_js_binding.cpp +) +target_include_directories({NAME}_binding PRIVATE ${{JERRY_INCLUDE_DIR}}) +target_link_libraries({NAME}_binding PUBLIC stdc++) +''' diff --git a/tools/module_generator/source_generator.py b/tools/module_generator/source_generator.py new file mode 100644 index 0000000000..9265f3af3f --- /dev/null +++ b/tools/module_generator/source_generator.py @@ -0,0 +1,985 @@ +#!/usr/bin/env python + +# Copyright 2019-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. + +import c_source_templates as c +import cpp_source_templates as cpp + +class CSourceGenerator(object): + def __init__(self): + self.function_names = [] + self.record_names = [] + self.variable_names = [] + self.enums = [] + self.constant_variables = [] + self.number_arrays = [] + self.namespace = [] + self.macros = [] + self.init_func_body = [] + self.global_records = [] + self.global_const_records = [] + + @property + def ns_name(self): + if self.namespace: + return '_'.join(self.namespace) + '_' + return '' + + @property + def parent_ns_name(self): + if self.namespace[:-1]: + return '_'.join(self.namespace[:-1]) + '_' + return '' + + @property + def scope_name(self): + if self.namespace: + return '::'.join(self.namespace) + '::' + return '' + + # methods for create/set a C variable + def js_to_char(self, _type, name, jval): + return c.JS_TO_CHAR.format(TYPE=_type, NAME=name, JVAL=jval) + + def js_set_char(self, name, jval): + return c.JS_SET_CHAR.format(NAME=name, JVAL=jval) + + def js_to_number(self, _type, name, jval): + return c.JS_TO_NUMBER.format(TYPE=_type, NAME=name, JVAL=jval) + + def js_set_number(self, name, jval): + return c.JS_SET_NUMBER.format(NAME=name, JVAL=jval) + + def js_to_bool(self, _type, name, jval): + return c.JS_TO_BOOL.format(TYPE=_type, NAME=name, JVAL=jval) + + def js_set_bool(self, name, jval): + return c.JS_SET_BOOL.format(NAME=name, JVAL=jval) + + def js_to_string(self, _type, name, jval): + return c.JS_TO_STRING.format(TYPE=_type, NAME=name, JVAL=jval) + + def js_free_string(self, name, jval): + return c.JS_FREE_STRING.format(NAME=name, JVAL=jval) + + def js_set_char_pointer(self, _type, name, jval): + return c.JS_SET_CHAR_PTR.format(TYPE=_type, NAME=name, JVAL=jval) + + def js_set_char_array(self, name, jval, size): + return c.JS_SET_CHAR_ARR.format(NAME=name, JVAL=jval, SIZE=size) + + def js_to_num_pointer(self, _type, name, jval): + return c.JS_TO_TYPEDARRAY.format(TYPE=_type, NAME=name, JVAL=jval) + + def js_free_buffer(self, name, jval): + return c.JS_FREE_BUFFER.format(NAME=name, JVAL=jval) + + def js_free_write_buffer(self, name, jval): + return c.JS_FREE_WRITE_BUFFER.format(NAME=name, JVAL=jval) + + def js_set_num_pointer(self, _type, name, jval): + return c.JS_SET_TYPEDARRAY.format(TYPE=_type, NAME=name, JVAL=jval) + + def js_to_record(self, _type, name, jval, record): + return c.JS_TO_RECORD.format(TYPE=_type, NAME=name, JVAL=jval, + RECORD=record) + + def js_set_record(self, _type, name, jval, record): + return c.JS_SET_RECORD.format(TYPE=_type, NAME=name, JVAL=jval, + RECORD=record) + + def js_set_const_record(self, _type, name, jval, record): + return c.JS_SET_CONST_RECORD.format(TYPE=_type, NAME=name, JVAL=jval, + RECORD=record) + + def js_to_record_ptr(self, _type, name, jval, record): + return c.JS_TO_RECORD_PTR.format(TYPE=_type, NAME=name, JVAL=jval, + RECORD=record) + + def js_to_function(self, func, name, jval, _type, params): + return c.JS_TO_FUNCTION.format(FUNC=func, NAME=name, JVAL=jval, + TYPE=_type, PARAMS=params) + + def js_cb_function(self, func, name, ret_t, params, length, create_val, + result, ret): + return c.JS_CB_FUNCTION.format(FUNC=func, NAME=name, RET_TYPE=ret_t, + PARAMS=params, LENGTH=length, RET=ret, + CREATE_VAL=create_val, RESULT=result) + + def js_to_unsupported(self, _type, name): + return c.JS_TO_UNSUPPORTED.format(TYPE=_type, NAME=name) + + def js_to_c(self, c_type, name, jval): + if c_type.is_char(): + return self.js_to_char(c_type.name, name, jval) + elif c_type.is_number() or c_type.is_enum(): + return self.js_to_number(c_type.name, name, jval) + elif c_type.is_bool(): + return self.js_to_bool(c_type.name, name, jval) + elif c_type.is_pointer(): + pointee = c_type.get_pointee_type() + if pointee.is_char(): + return self.js_to_string(pointee.name, name, jval) + elif pointee.is_number(): + return self.js_to_num_pointer(pointee.name, name, jval) + elif pointee.is_record(): + record = pointee.get_as_record_decl().ns_name + return self.js_to_record_ptr(pointee.name, name, jval, record) + elif c_type.is_record(): + record = c_type.get_as_record_decl().ns_name + return self.js_to_record(c_type.name, name, jval, record) + + return self.js_to_unsupported(c_type.name, name) + + def js_set_c(self, c_type, name, jval): + if c_type.is_char(): + return self.js_set_char(name, jval) + elif c_type.is_number() or c_type.is_enum(): + return self.js_set_number(name, jval) + elif c_type.is_bool(): + return self.js_set_bool(name, jval) + elif c_type.is_pointer(): + pointee = c_type.get_pointee_type() + if c_type.is_array(): + size = c_type.get_array_size() - 1 + if pointee.is_char(): + return self.js_set_char_array(name, jval, size) + elif pointee.is_number(): + return self.js_set_num_pointer(pointee.name, name, jval) + else: + if pointee.is_char(): + return self.js_set_char_pointer(pointee.name, name, jval) + elif pointee.is_number(): + return self.js_set_num_pointer(pointee.name, name, jval) + elif c_type.is_record(): + record = c_type.get_as_record_decl().ns_name + if c_type.has_const_member(): + return self.js_set_const_record(c_type.name, name, jval, record) + return self.js_set_record(c_type.name, name, jval, record) + + return self.js_to_unsupported(c_type.name, name) + + + # methods for create a JS variable + def void_to_js(self, name): + return c.JS_CREATE_VAL.format(NAME=name, TYPE='undefined', FROM='') + + def char_to_js(self, name, cval): + return c.JS_CREATE_CHAR.format(NAME=name, FROM=cval) + + def number_to_js(self, name, cval): + return c.JS_CREATE_VAL.format(NAME=name, TYPE='number', FROM=cval) + + def bool_to_js(self, name, cval): + return c.JS_CREATE_VAL.format(NAME=name, TYPE='boolean', FROM=cval) + + def string_to_js(self, name, cval): + return c.JS_CREATE_STRING.format(NAME=name, FROM=cval) + + def num_pointer_to_js(self, name, cval, _type): + return c.JS_CREATE_TYPEDARRAY.format(NAME=name, FROM=cval, TYPE=_type, + ARRAY_TYPE=c.TYPEDARRAYS[_type]) + + def record_to_js(self, name, cval, _type, record): + return c.JS_CREATE_OBJECT.format(NAME=name, FROM=cval, TYPE=_type, + RECORD=record) + + def const_record_to_js(self, name, cval, _type, record): + return c.JS_CREATE_CONST_OBJECT.format(NAME=name, FROM=cval, TYPE=_type, + RECORD=record) + + def unsupported_to_js(self, name, cval): + return c.JS_CREATE_UNSUPPORTED.format(NAME=name, FROM=cval) + + def c_to_js(self, c_type, cval, name): + if c_type.is_void(): + return self.void_to_js(name) + elif c_type.is_char(): + return self.char_to_js(name, cval) + elif c_type.is_number() or c_type.is_enum(): + return self.number_to_js(name, cval) + elif c_type.is_bool(): + return self.bool_to_js(name, cval) + elif c_type.is_pointer(): + pointee = c_type.get_pointee_type() + if pointee.is_char(): + return self.string_to_js(name, cval) + elif pointee.is_number(): + return self.num_pointer_to_js(name, cval, pointee.name) + elif c_type.is_record(): + record = c_type.get_as_record_decl().ns_name + if c_type.has_const_member(): + return self.const_record_to_js(name, cval, c_type.name, record) + return self.record_to_js(name, cval, c_type.name, record) + + return self.unsupported_to_js(name, cval) + + def js_record_destructor(self, _type, record): + return c.JS_RECORD_DESTRUCTOR.format(TYPE=_type, RECORD=record) + + def js_record_member(self, _type, record, name, body): + return c.JS_RECORD_MEMBER.format(TYPE=_type, RECORD=record, NAME=name, + BODY=body) + + def js_record_getter(self, name, record): + return c.JS_RECORD_GETTER.format(NAME=name, RECORD=record) + + def js_record_creator(self, _type, record, regist): + return c.JS_RECORD_CREATOR.format(TYPE=_type, RECORD=record, + REGIST=regist) + + def js_record_constructor_c(self, _type, record, body): + return c.JS_RECORD_CONSTRUCTOR.format(TYPE=_type, RECORD=record, + BODY=body) + + def js_record_return(self, record): + return c.JS_RECORD_RETURN.format(RECORD=record) + + def js_get_prop_struct(self, name, _type, get_val, init=''): + return c.JS_GET_PROP_STRUCT.format(NAME=name, TYPE=_type, + GET_VAL=get_val, INIT=init) + + def js_get_prop_union(self, name, _type, get_val, ret, init=''): + return c.JS_GET_PROP_UNION.format(NAME=name, TYPE=_type, + GET_VAL=get_val, RET=ret, INIT=init) + + def js_init_members(self, _type, members): + return c.JS_INIT_MEMBERS.format(TYPE=_type, MEMBERS=members) + + def js_init_members_const(self, _type, members): + return c.JS_INIT_MEMBERS_CONST.format(TYPE=_type, MEMBERS=members) + + def js_regist_member(self, record, name): + return c.JS_REGIST_MEMBER.format(RECORD=record, NAME=name) + + def js_regist_record(self, name, record, ref, object): + return c.JS_REGIST_RECORD.format(NAME=name, RECORD=record, REF=ref, + OBJECT=object) + + def js_regist_const_member(self, name): + return c.JS_REGIST_CONST_MEMBER.format(NAME=name) + + def js_regist_const_record(self, name, object, value): + return c.JS_REGIST_CONST_RECORD.format(NAME=name, OBJECT=object, + VALUE=value) + + def js_regist_num_arr_member(self, name, _type, size): + return c.JS_REGIST_ARR_MEMBER.format(NAME=name, TYPE=_type, SIZE=size, + ARRAY_TYPE=c.TYPEDARRAYS[_type]) + + def create_member_getter_setter(self, member, record): + name = 'native_ptr->' + member.name + record_name = self.ns_name + record.name + + if member.type.is_record(): + getter = self.js_record_getter(member.name, record_name + '_') + if member.type.has_const_member(): + return getter + else: + get_result = self.c_to_js(member.type, name, 'ret_val') + getter = self.js_record_member(record.type.name, record_name, + member.name + '_getter', get_result) + + set_result = self.js_check_type(member.type, 'args_p[0]', + member.name + '_setter') + set_result += self.js_set_c(member.type, name, 'args_p[0]') + set_result += ' jerry_value_t ret_val = jerry_create_undefined();' + setter = self.js_record_member(record.type.name, record_name, + member.name + '_setter', set_result) + + return getter + setter + + def create_record_constructor(self, record): + name = self.ns_name + record.name + type_name = record.type.name + is_struct = record.type.is_struct() + is_union = record.type.is_union() + has_const_member = record.type.has_const_member() + constructor = [] + members = [] + free = [] + + for member in record.field_decls: + m_name = member.name + m_type = member.type + jval = '{}_value'.format(m_name) + init = '' + get_val = self.js_set_c(m_type, m_name, jval) + + if m_type.is_array(): + size = m_type.get_array_size() + init_array = ['{' + m_name + '[0]'] + for i in range(size-2): + init_array.append('{}[{}]'.format(m_name, i+1)) + init_array.append('{}[{}]}}'.format(m_name, size-1)) + init_array = (', ').join(init_array) + members.append(init_array) + m_type = m_type.get_array_type() + init = '[{}]'.format(size) + if is_union: + if has_const_member: + get_val += self.js_init_members_const(type_name, + init_array) + else: + get_val += self.js_init_members(type_name, init_array) + else: + members.append(m_name) + if member.type.is_record(): + if not member.type.get_as_record_decl().has_constructor(): + init = ' = {}' + if is_union: + if has_const_member: + get_val += self.js_init_members_const(type_name, m_name) + else: + get_val += self.js_init_members(type_name, m_name) + if m_type.is_pointer(): + if m_type.get_pointee_type().is_char(): + free.append(self.js_free_string(m_name, jval)) + if is_union: + get_val += self.js_free_string(m_name, jval) + elif m_type.get_pointee_type().is_number(): + free.append(self.js_free_buffer(m_name, jval)) + if is_union: + get_val += self.js_free_buffer(m_name, jval) + + if is_struct: + constructor.append(self.js_get_prop_struct(m_name, m_type.name, + get_val, init)) + elif is_union: + ret = self.js_record_return(name) + constructor.append(self.js_get_prop_union(m_name, m_type.name, + get_val, ret, init)) + constructor = ('').join(constructor) + members = (', ').join(members) + free = ('').join(free) + if has_const_member: + members = self.js_init_members_const(type_name, members) + else: + members = self.js_init_members(type_name, members) + if is_struct: + body = constructor + members + free + elif is_union: + body = constructor + + return self.js_record_constructor_c(type_name, name, body) + + def create_record(self, record): + name = record.name + type_name = record.type.name + self.record_names.append(name) + result = [self.js_record_destructor(type_name, name)] + regist = [] + + for member in record.field_decls: + m_name = member.name + m_type = member.type + if m_type.is_const(): + cval = 'native_ptr->' + m_name + jval = m_name + '_js' + regist.append(self.c_to_js(m_type, cval, jval)) + regist.append(self.js_regist_const_member(m_name)) + elif m_type.get_array_type().is_number(): + arr_name = m_type.get_array_type().name + size = m_type.get_array_size() + regist.append(self.js_regist_num_arr_member(m_name, arr_name, + size)) + else: + get_set = self.create_member_getter_setter(member, record) + result.append(get_set) + if m_type.is_record(): + r_name = m_type.get_as_record_decl().ns_name + ref = 'native_ptr->{}'.format(m_name) + regist.append(self.js_regist_record(m_name, r_name, ref, + 'js_obj')) + if m_type.has_const_member(): + r_name = name + '_' + m_name + regist.append(self.js_regist_const_record(r_name, + 'js_obj', + m_name)) + else: + regist.append(self.js_regist_member(name, m_name)) + else: + regist.append(self.js_regist_member(name, m_name)) + + regist = ('').join(regist) + result.append(self.js_record_creator(type_name, name, regist)) + result.append(self.create_record_constructor(record)) + + return '\n'.join(result) + + def create_c_function(self, func, funcname, name): + params = [] + create_val = [] + res= '' + ret = '' + + for index, param in enumerate(func.params): + param_name = 'p_{}'.format(index) + arg_name = 'arg_{}'.format(index) + params.append(param.type.name + ' ' + param_name) + create_val.append(self.c_to_js(param.type, param_name, arg_name)) + create_val.append(' args[{}] = {};'.format(index, arg_name)) + + if not func.return_type.is_void(): + res = self.js_to_c(func.return_type, 'ret', 'result') + ret = 'ret' + + return self.js_cb_function(funcname, name, func.return_type.name, + (', ').join(params), len(func.params), + ('\n').join(create_val), res, ret) + + def js_ext_func(self, name, body): + return c.JS_EXT_FUNC.format(NAME=name, BODY=body) + + def js_check_arg_count(self, count, func): + return c.JS_CHECK_ARG_COUNT.format(COUNT=count, FUNC=func) + + def js_check_type(self, c_type, jval, func): + _type = '' + template = c.JS_CHECK_TYPE + if c_type.is_char(): + _type = 'string' + elif c_type.is_number() or c_type.is_enum(): + _type = 'number' + elif c_type.is_record(): + _type = 'object' + elif c_type.is_function(): + template = c.JS_CHECK_POINTER + _type = 'function' + elif c_type.is_pointer(): + template = c.JS_CHECK_POINTER + if c_type.get_pointee_type().is_char(): + _type = 'string' + elif c_type.get_pointee_type().is_number(): + _type = 'typedarray' + elif c_type.get_pointee_type().is_function(): + _type = 'function' + elif c_type.get_pointee_type().is_record(): + _type = 'object' + + if _type: + return template.format(TYPE=_type, JVAL=jval, FUNC=func) + return '' + + def get_val_from_param(self, param, funcname, name, jval): + buff = [] + callback = '' + if (param.type.is_pointer() and + param.type.get_pointee_type().is_function()): + func = param.get_as_function() + ret_type = func.return_type.name + params = ', '.join([p.type.name for p in func.params]) + result = self.js_to_function(funcname, name, jval, ret_type, params) + callback = self.create_c_function(func, funcname, name) + elif param.type.is_function(): + func = param.get_as_function() + ret_type = func.return_type.name + params = ', '.join([p.type.name for p in func.params]) + result = self.js_to_function(funcname, name, jval, ret_type, params) + callback = self.create_c_function(func, funcname, name) + else: + result = self.js_to_c(param.type, name, jval) + if param.type.is_pointer(): + if param.type.get_pointee_type().is_char(): + buff.append(self.js_free_string(name, jval)) + if param.type.get_pointee_type().is_number(): + buff.append(self.js_free_write_buffer(name, jval)) + + return result, buff, callback + + def create_ext_function(self, function): + self.function_names.append(function.name) + funcname = function.name + params = function.params + return_type = function.return_type + jerry_function = [] + native_params = [] + buffers_to_free = [] + callbacks = [] + + jerry_function.append(self.js_check_arg_count(len(params), funcname)) + + for index, param in enumerate(params): + jval = 'args_p[{}]'.format(index) + native_name = 'arg_{}'.format(index) + check_type = self.js_check_type(param.type, jval, funcname) + + result = self.get_val_from_param(param, funcname, native_name, jval) + buffers_to_free += result[1] + callbacks.append(result[2]) + native_params.append(native_name) + jerry_function.append(check_type + result[0]) + + native_params = (', ').join(native_params) + + if return_type.is_void(): + native_call = ' {} ({});\n'.format(funcname, native_params) + else: + native_call = ' {} {} = {} ({});\n'.format(return_type.name, + 'result', funcname, + native_params) + + jerry_function.append(' // native function call\n' + native_call) + jerry_function += buffers_to_free + + result = self.c_to_js(return_type, 'result', 'ret_val') + + jerry_function.append(result) + + callbacks = '\n'.join(callbacks) + jerry_function = '\n'.join(jerry_function) + ext_func = self.js_ext_func(funcname + '_handler', jerry_function) + + return callbacks + ext_func + + def create_getter_setter(self, var): + if var.type.is_const(): + self.constant_variables.append(var) + return '' + elif var.type.get_array_type().is_number(): + self.number_arrays.append(var) + return '' + + ns_name = self.ns_name + var.name + scope_name = self.scope_name + var.name + + if var.type.is_record(): + record = var.type.get_as_record_decl().ns_name + self.global_records.append((var.name, record)) + getter = self.js_record_getter(ns_name, '') + if var.type.has_const_member(): + self.global_const_records.append(var.name) + return getter + else: + get_result = self.c_to_js(var.type, scope_name, 'ret_val') + getter = self.js_ext_func(ns_name + '_getter', get_result) + + self.variable_names.append(var.name) + set_result = self.js_check_type(var.type, 'args_p[0]', + ns_name + '_setter') + set_result += self.js_set_c(var.type, scope_name, 'args_p[0]') + set_result += ' jerry_value_t ret_val = jerry_create_undefined();' + + setter = self.js_ext_func(ns_name + '_setter', set_result) + + return getter + setter + + def init_func(self, name, body): + return c.INIT_FUNC.format(NAME=name, BODY=body) + + def init_regist_func(self, name, object, func): + return c.INIT_REGIST_FUNC.format(NAME=name, OBJECT=object, FUNC=func) + + def init_regist_record(self, name, object, record): + return c.INIT_REGIST_RECORD.format(NAME=name, OBJECT=object, + RECORD=record) + + def init_regist_enum(self, name, object, ref, enum): + return c.INIT_REGIST_ENUM.format(NAME=name, OBJECT=object, REF=ref, + ENUM=enum) + + def init_regist_value(self, name, object, value): + return c.INIT_REGIST_VALUE.format(NAME=name, OBJECT=object, VALUE=value) + + def init_regist_const(self, name, object, value): + return c.INIT_REGIST_CONST.format(NAME=name, OBJECT=object, VALUE=value) + + def init_regist_num_arr(self, name, object, ref, arr, _type, size): + return c.INIT_REGIST_NUM_ARR.format(NAME=name, OBJECT=object, REF=ref, + ARR=arr, TYPE=_type, SIZE=size, + ARRAY_TYPE=c.TYPEDARRAYS[_type]) + + def init_create_object(self, name): + return c.INIT_CREATE_OBJECT.format(NAME=name) + + def init_regist_object(self, name, ref, object): + return c.INIT_REGIST_OBJECT.format(NAME=name, REF=ref, OBJECT=object) + + def create_ns_obj(self): + self.init_func_body.append(self.init_create_object(self.ns_name)) + + def regist_ns_obj(self): + if self.namespace: + name = self.ns_name + ref = self.namespace[-1] + object = '{}object'.format(self.parent_ns_name) + self.init_func_body.append(self.init_regist_object(name, ref, + object)) + + def create_init_function_body(self): + object = '{}object'.format(self.ns_name) + + for funcname in self.function_names: + name = self.ns_name + funcname + self.init_func_body.append(self.init_regist_func(name, object, + funcname)) + + for record in self.record_names: + name = self.ns_name + record + self.init_func_body.append(self.init_regist_record(name, object, + record)) + + for varname in self.variable_names: + name = self.ns_name + varname + self.init_func_body.append(self.init_regist_value(name, object, + varname)) + + for glob_record in self.global_records: + name = self.ns_name + glob_record[0] + ref = self.scope_name + glob_record[0] + record = glob_record[1] + self.init_func_body.append(self.js_regist_record(name, record, ref, + object)) + + for c_record in self.global_const_records: + name = self.ns_name + c_record + self.init_func_body.append(self.js_regist_const_record(name, object, + c_record)) + + for array in self.number_arrays: + name = self.ns_name + array.name + ref = self.scope_name + array.name + typename = array.type.get_array_type().name + size = array.type.get_array_size() + self.init_func_body.append(self.init_regist_num_arr(name, object, + ref, array.name, + typename, size)) + + for var in self.constant_variables: + name = self.ns_name + var.name + ref = self.scope_name + var.name + jval = '{}_js'.format(name) + self.init_func_body.append(self.c_to_js(var.type, ref, jval)) + self.init_func_body.append(self.init_regist_const(name, object, + var.name)) + + for enum in self.enums: + name = self.ns_name + enum + ref = self.scope_name + enum + self.init_func_body.append(self.init_regist_enum(name, object, ref, + enum)) + + for macro in self.macros: + name = macro.name + jval = '{}_js'.format(name) + if macro.is_char(): + create_val = ' char {N}_value = {N};'.format(N=name) + value = '{}_value'.format(name) + self.init_func_body.append(create_val) + self.init_func_body.append(self.char_to_js(jval, value)) + self.init_func_body.append(self.init_regist_const(name, object, + name)) + elif macro.is_string(): + self.init_func_body.append(self.string_to_js(jval, name)) + self.init_func_body.append(self.init_regist_const(name, object, + name)) + elif macro.is_number(): + self.init_func_body.append(self.number_to_js(jval, name)) + self.init_func_body.append(self.init_regist_const(name, object, + name)) + + del self.function_names[:] + del self.record_names[:] + del self.variable_names[:] + del self.global_records[:] + del self.global_const_records[:] + del self.number_arrays[:] + del self.constant_variables[:] + del self.enums[:] + del self.macros[:] + + def create_init_function(self, dirname): + return self.init_func(dirname, ('\n').join(self.init_func_body)) + + + +class CppSourceGenerator(CSourceGenerator): + def __init__(self): + CSourceGenerator.__init__(self) + self.class_names = [] + + def js_to_string(self, _type, name, jval): + return cpp.JS_TO_STRING.format(TYPE=_type, NAME=name, JVAL=jval) + + def js_free_string(self, name, jval): + return cpp.JS_FREE_STRING.format(NAME=name, JVAL=jval) + + def js_set_char_pointer(self, _type, name, jval): + return cpp.JS_SET_CHAR_PTR.format(TYPE=_type, NAME=name, JVAL=jval) + + def js_to_num_pointer(self, _type, name, jval): + return cpp.JS_TO_TYPEDARRAY.format(TYPE=_type, NAME=name, JVAL=jval) + + def js_free_write_buffer(self, name, jval): + return cpp.JS_FREE_WRITE_BUFFER.format(NAME=name, JVAL=jval) + + def js_set_num_pointer(self, _type, name, jval): + return cpp.JS_SET_TYPEDARRAY.format(TYPE=_type, NAME=name, JVAL=jval) + + def js_return_object(self, name, record, cval): + return cpp.JS_RETURN_OBJECT.format(NAME=name, RECORD=record, FROM=cval) + + def js_alloc_record(self, record, name): + return cpp.JS_ALLOC_RECORD.format(RECORD=record, NAME=name) + + def js_value_is(self, c_type, jval): + if c_type.is_char(): + return cpp.JS_VALUE_IS.format(TYPE='string', JVAL=jval) + elif c_type.is_number() or c_type.is_enum(): + return cpp.JS_VALUE_IS.format(TYPE='number', JVAL=jval) + elif c_type.is_bool(): + return cpp.JS_VALUE_IS.format(TYPE='boolean', JVAL=jval) + elif c_type.is_record(): + record = c_type.get_as_record_decl().ns_name + return cpp.JS_VALUE_IS.format(TYPE=record, JVAL=jval) + elif c_type.is_function(): + return cpp.JS_POINTER_IS.format(TYPE='function', JVAL=jval) + elif c_type.is_pointer(): + if c_type.get_pointee_type().is_char(): + return cpp.JS_POINTER_IS.format(TYPE='string', JVAL=jval) + elif c_type.get_pointee_type().is_number(): + return cpp.JS_POINTER_IS.format(TYPE='typedarray', JVAL=jval) + elif c_type.get_pointee_type().is_function(): + return cpp.JS_POINTER_IS.format(TYPE='function', JVAL=jval) + elif c_type.get_pointee_type().is_record(): + record = c_type.get_pointee_type().get_as_record_decl().ns_name + return cpp.JS_POINTER_IS.format(TYPE=record, JVAL=jval) + return '' + + def js_check_record(self, record): + return cpp.JS_CHECK_RECORD.format(RECORD=record) + + def js_record_destructor(self, _type, record): + return cpp.JS_RECORD_DESTRUCTOR.format(TYPE=_type, RECORD=record) + + def js_record_constructor_cpp(self, _type, record, case, suff = ''): + return cpp.JS_RECORD_CONSTRUCTOR.format(TYPE=_type, RECORD=record, + CASE=case, SUFF=suff) + + def js_constr_call(self, condition, get_val, name, params, free): + return cpp.JS_CONSTR_CALL.format(CONDITION=condition, GET_VAL=get_val, + NAME=name, PARAMS=params, FREE=free) + + def js_constr_case_0(self, name): + return cpp.JS_CONSTR_CASE_0.format(NAME=name) + + def js_constr_case(self, num, calls, name): + return cpp.JS_CONSTR_CASE.format(NUM=num, CALLS=calls, NAME=name) + + def js_regist_method(self, record, name): + return cpp.JS_REGIST_METHOD.format(RECORD=record, NAME=name) + + def js_regist_const_member(self, record, name): + return cpp.JS_REGIST_CONST_MEMBER.format(RECORD=record, NAME=name) + + def js_record_method(self, record, name, _type, result, case, ret_val, + suff): + return cpp.JS_RECORD_METHOD.format(RECORD=record, NAME=name, TYPE=_type, + RESULT=result, CASE=case, + RET_VAL=ret_val, SUFF=suff) + + def js_method_call(self, condition, get_val, result, name, params, free): + return cpp.JS_METHOD_CALL.format(CONDITION=condition, GET_VAL=get_val, + RESULT=result, NAME=name, + PARAMS=params, FREE=free) + + def js_method_case_0(self, result, name): + return cpp.JS_METHOD_CASE_0.format(RESULT=result, NAME=name) + + def js_method_case(self, num, calls, record, name): + return cpp.JS_METHOD_CASE.format(NUM=num, CALLS=calls, RECORD=record, + NAME=name) + + def js_ext_cpp_func(self, name, result, case, ret_val, suff): + return cpp.JS_EXT_CPP_FUNC.format(NAME=name, RESULT=result, CASE=case, + RET_VAL=ret_val, SUFF=suff) + + def js_func_call(self, condition, get_val, result, name, params, free): + return cpp.JS_FUNC_CALL.format(CONDITION=condition, GET_VAL=get_val, + RESULT=result, NAME=name, PARAMS=params, + FREE=free) + + def js_func_case_0(self, result, name): + return cpp.JS_FUNC_CASE_0.format(RESULT=result, NAME=name) + + def js_func_case(self, num, calls, name): + return cpp.JS_FUNC_CASE.format(NUM=num, CALLS=calls, NAME=name) + + def create_record(self, record): + name = record.name + ns_name = self.ns_name + name + record_type = record.type.name + result = [self.js_record_destructor(record_type, ns_name), + self.js_check_record(ns_name)] + regist = [] + + for member in record.field_decls: + m_name = member.name + if member.type.is_const(): + cval = 'native_ptr->' + m_name + jval = name + '_' + m_name + '_js' + regist.append(self.c_to_js(member.type, cval, jval)) + regist.append(self.js_regist_const_member(name, m_name)) + elif member.type.get_array_type().is_number(): + arr_name = member.type.get_array_type().name + size = member.type.get_array_size() + regist.append(self.js_regist_num_arr_member(m_name, arr_name, + size)) + else: + get_set = self.create_member_getter_setter(member, record) + result.append(get_set) + if member.type.is_record(): + r_name = member.type.get_as_record_decl().ns_name + ref = 'native_ptr->{}'.format(m_name) + regist.append(self.js_regist_record(m_name, r_name, ref, + 'js_obj')) + if member.type.has_const_member(): + r_name = ns_name + '_' + m_name + regist.append(self.js_regist_const_record(r_name, + 'js_obj', + m_name)) + else: + regist.append(self.js_regist_member(ns_name, m_name)) + else: + regist.append(self.js_regist_member(ns_name, m_name)) + + for method in record.methods: + result.append(self.create_ext_function(method, name, record_type, + is_method=True)) + regist.append(self.js_regist_method(ns_name, + method.name + method.suffix)) + + regist = ('\n').join(regist) + result.append(self.js_record_creator(record_type, ns_name, regist)) + + if record.has_constructor(): + if not record.constructors: + self.record_names.append(name) + cases = self.js_constr_case_0(self.scope_name + name) + result.append(self.js_record_constructor_cpp(record_type, + ns_name, cases)) + else: + for constr in record.constructors: + self.record_names.append(name + constr.suffix) + cases = self.create_ext_function(constr, name, + is_constructor=True) + result.append(self.js_record_constructor_cpp(record_type, + ns_name, cases, + constr.suffix)) + else: + self.record_names.append(name) + result.append(self.create_record_constructor(record)) + + return '\n'.join(result) + + def create_ext_function(self, func, record_name = None, record_type = None, + is_constructor = False, is_method = False): + name = func.name if not is_constructor else record_name + scope_name = self.scope_name + name + cases = [] + callbacks = [] + if not is_constructor: + ret_type = func.return_type + if ret_type.is_void(): + result = '' + elif ret_type.is_record(): + result = '*result = ' + else: + result = 'result = ' + + if is_constructor and 0 in func.params: + cases.append(self.js_constr_case_0(scope_name)) + if func.params: + del func.params[0] + elif is_method and 0 in func.params: + cases.append(self.js_method_case_0(result, name)) + del func.params[0] + elif 0 in func.params: + cases.append(self.js_func_case_0(result, scope_name)) + del func.params[0] + + for parm_len, param_lists in func.params.items(): + calls = [] + for param_list in param_lists: + get_val = '' + condition = [] + native_params = [] + free_buffers = [] + for index, param in enumerate(param_list): + jval = 'args_p[{}]'.format(index) + p_name = 'arg_{}'.format(index) + condition.append(self.js_value_is(param.type, jval)) + + res = self.get_val_from_param(param, name, p_name, jval) + get_val += res[0] + free_buffers += res[1] + callbacks.append(res[2]) + native_params.append(p_name) + + native_params = (', ').join(native_params) + condition = (' && ').join(condition) + free_buffers = ('\n').join(free_buffers) + + if is_constructor: + calls.append(self.js_constr_call(condition, get_val, + scope_name, native_params, + free_buffers)) + elif is_method: + calls.append(self.js_method_call(condition, get_val, result, + name, native_params, + free_buffers)) + else: + calls.append(self.js_func_call(condition, get_val, result, + scope_name, native_params, + free_buffers)) + calls = ('\n').join(calls) + if is_constructor: + cases.append(self.js_constr_case(parm_len, calls, name)) + elif is_method: + cases.append(self.js_method_case(parm_len, calls, record_name, + name)) + else: + cases.append(self.js_func_case(parm_len, calls, name)) + + callbacks = '\n'.join(callbacks) + cases = ''.join(cases) + + if is_constructor: + return cases + + if ret_type.is_record(): + record = ret_type.get_as_record_decl() + if record.has_default_constructor(): + result = '{T}* result = new {T}();'.format(T=ret_type.name) + else: + result = self.js_alloc_record(ret_type.name, 'result') + ns_name = self.ns_name + record.name + ret_val = self.js_return_object('ret_val', ns_name, 'result') + else: + if not ret_type.is_void(): + result = '{} result;'.format(ret_type.name) + ret_val = self.c_to_js(ret_type, 'result', 'ret_val') + + if is_method: + return self.js_record_method(self.ns_name + record_name, name, + record_type, result, cases, ret_val, + func.suffix) + else: + self.function_names.append(name + func.suffix) + return callbacks + self.js_ext_cpp_func(self.ns_name + name, result, + cases, ret_val, func.suffix) + + def init_func(self, name, body): + return cpp.INIT_FUNC.format(NAME=name, BODY=body) diff --git a/tools/module_templates/basic_module_template/js/module.js b/tools/module_templates/basic_module_template/js/module.js new file mode 100644 index 0000000000..33d708a4f7 --- /dev/null +++ b/tools/module_templates/basic_module_template/js/module.js @@ -0,0 +1,29 @@ +/* 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. + */ + +/** + * To export an object/value use the 'module.exports' object. + */ +var demo_value = "Hello"; + +/* Export an object with two properties. */ +module.exports = { + /* the 'native' means the object returned by the C init method. */ + demo2: function() { return native.message; }, + add: native.add +} + +/* Export a local variable. */ +module.exports.demo_value = demo_value; diff --git a/tools/module_templates/basic_module_template/module.cmake b/tools/module_templates/basic_module_template/module.cmake new file mode 100644 index 0000000000..9a6e3b30f4 --- /dev/null +++ b/tools/module_templates/basic_module_template/module.cmake @@ -0,0 +1,41 @@ +# 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. + +# General variables usable from IoT.js cmake: +# - TARGET_ARCH - the target architecture (as specified during cmake step) +# - TARGET_BOARD - the target board(/device) +# - TARGET_OS - the target operating system +# +# Module related variables usable from IoT.js cmake: +# - MODULE_DIR - the modules root directory +# - MODULE_BINARY_DIR - the build directory for the current module +# - MODULE_LIBS - list of libraries to use during linking (set this) +set(MODULE_NAME "$MODULE_NAME$") + +# DO NOT include the source files which are already in the modules.json file. + +# If the module builds its own files into a lib please use the line below. +# Note: the subdir 'lib' should contain the CMakeLists.txt describing how the +# module should be built. +#add_subdirectory(${MODULE_DIR}/lib/ ${MODULE_BINARY_DIR}/${MODULE_NAME}) + +# If you wish to link external libraries please add it to +# the MODULE_LIBS list. +# +# IMPORTANT! +# if the module builds its own library that should also be specified! +# +# Example (to add the 'demo' library for linking): +# +# list(APPEND MODULE_LIBS demo) diff --git a/tools/module_templates/basic_module_template/modules.json b/tools/module_templates/basic_module_template/modules.json new file mode 100644 index 0000000000..a9acb4b0f7 --- /dev/null +++ b/tools/module_templates/basic_module_template/modules.json @@ -0,0 +1,10 @@ +{ + "modules": { + "$MODULE_NAME$": { + "js_file": "js/module.js", + "native_files": ["src/module.c"], + "init": "Init$MODULE_NAME$", + "cmakefile": "module.cmake" + } + } +} diff --git a/tools/module_templates/basic_module_template/src/module.c b/tools/module_templates/basic_module_template/src/module.c new file mode 100644 index 0000000000..608764dd38 --- /dev/null +++ b/tools/module_templates/basic_module_template/src/module.c @@ -0,0 +1,53 @@ +/* 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_def.h" + +/** + * Demo method + */ +static jerry_value_t demo_method( + const jerry_value_t func_value, /**< function object */ + const jerry_value_t this_value, /**< this arg */ + const jerry_value_t *args_p, /**< function arguments */ + const jerry_length_t args_cnt) /**< number of function arguments */ +{ + if (args_cnt < 2) { + static char *error_msg = "Incorrect parameter count"; + return jerry_create_error(JERRY_ERROR_TYPE, + (const jerry_char_t *)error_msg); + } + + if (!jerry_value_is_number(args_p[0]) || !jerry_value_is_number(args_p[1])) { + static char *error_msg = "Incorrect parameter type(s)"; + return jerry_create_error(JERRY_ERROR_TYPE, + (const jerry_char_t *)error_msg); + } + + int arg_a = jerry_get_number_value(args_p[0]); + int arg_b = jerry_get_number_value(args_p[1]); + + return jerry_create_number(arg_a + arg_b); +} + +/** + * Init method called by IoT.js + */ +jerry_value_t Init$MODULE_NAME$() { + jerry_value_t mymodule = jerry_create_object(); + iotjs_jval_set_property_string_raw(mymodule, "message", "Hello world!"); + iotjs_jval_set_method(mymodule, "add", demo_method); + return mymodule; +} diff --git a/tools/module_templates/shared_module_template/CMakeLists.txt b/tools/module_templates/shared_module_template/CMakeLists.txt new file mode 100644 index 0000000000..7585c2e446 --- /dev/null +++ b/tools/module_templates/shared_module_template/CMakeLists.txt @@ -0,0 +1,33 @@ +# 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. + +# +# This is a standalone shared libray which +# only requires the iotjs and jerry header file(s). +# +cmake_minimum_required(VERSION 2.8) +set(NAME $MODULE_NAME$) + +set(IOTJS_INCLUDE_DIR "$IOTJS_PATH$/include") + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") + +add_library(${NAME} SHARED + src/module_entry.c) +target_include_directories(${NAME} + PRIVATE ${IOTJS_INCLUDE_DIR} ${JERRY_INCLUDE_DIR}) +set_target_properties(${NAME} PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" + PREFIX "" + SUFFIX ".node") diff --git a/tools/module_templates/shared_module_template/README.md b/tools/module_templates/shared_module_template/README.md new file mode 100644 index 0000000000..1452602a1c --- /dev/null +++ b/tools/module_templates/shared_module_template/README.md @@ -0,0 +1,18 @@ +# IoT.js module: $MODULE_NAME$ + +## How to build? + +In the source directory of the module: + +```sh +$ cmake -Bbuild -H. +$ make -C build +``` + +## How to test? + +In the source directory of the module: + +```sh +$ iotjs js/test.js +``` diff --git a/src/iotjs_exception.h b/tools/module_templates/shared_module_template/js/test.js similarity index 72% rename from src/iotjs_exception.h rename to tools/module_templates/shared_module_template/js/test.js index 6be79165bb..9f328cbb82 100644 --- a/src/iotjs_exception.h +++ b/tools/module_templates/shared_module_template/js/test.js @@ -1,4 +1,4 @@ -/* Copyright 2015-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. @@ -13,11 +13,8 @@ * limitations under the License. */ -#ifndef IOTJS_EXCEPTION_H -#define IOTJS_EXCEPTION_H +var console = require("console"); +var demo_module = require("build/lib/$MODULE_NAME$"); +console.log(demo_module.hello()); -iotjs_jval_t iotjs_create_uv_exception(int errorno, const char* syscall); - - -#endif /* IOTJS_EXCEPTION_H */ diff --git a/tools/module_templates/shared_module_template/src/module_entry.c b/tools/module_templates/shared_module_template/src/module_entry.c new file mode 100644 index 0000000000..ed1120486c --- /dev/null +++ b/tools/module_templates/shared_module_template/src/module_entry.c @@ -0,0 +1,40 @@ +/* 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 +#include + +static napi_value hello_world(napi_env env, napi_callback_info info) { + napi_value world; + const char* str = "Hello world!"; + size_t str_len = strlen(str); + + if (napi_create_string_utf8(env, str, str_len, &world) != napi_ok) + return NULL; + + return world; +} + +napi_value init_$MODULE_NAME$(napi_env env, napi_value exports) { + napi_property_descriptor desc = { "hello", 0, hello_world, 0, + 0, 0, napi_default, 0 }; + + if (napi_define_properties(env, exports, 1, &desc) != napi_ok) + return NULL; + + return exports; +} + +NAPI_MODULE($MODULE_NAME$, init_$MODULE_NAME$) diff --git a/tools/precommit.py b/tools/precommit.py deleted file mode 100755 index d64708e41c..0000000000 --- a/tools/precommit.py +++ /dev/null @@ -1,205 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-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. - -from __future__ import print_function - -import argparse -import sys -import os -import json -from common_py import path -from common_py.system.filesystem import FileSystem as fs -from common_py.system.executor import Executor as ex -from common_py.system.platform import Platform -from check_tidy import check_tidy - -TESTS=['host-linux', 'host-darwin', 'rpi2', 'nuttx', 'misc', - 'artik10', 'coverity'] -BUILDTYPES=['debug', 'release'] -NUTTXTAG = 'nuttx-7.19' - -def get_config(): - config_path = path.BUILD_CONFIG_PATH - with open(config_path, 'r') as f: - config = json.loads(f.read().encode('ascii')) - return config - - -def parse_option(): - parser = argparse.ArgumentParser( - description='IoT.js pre-commit script.', - epilog='If no arguments are given, runs full test.') - parser.add_argument('--test', choices=TESTS, action='append') - parser.add_argument('--buildtype', choices=BUILDTYPES, action='append') - parser.add_argument('--buildoptions', action='store', default='', - help='A comma separated list of extra buildoptions') - - option = parser.parse_args(sys.argv[1:]) - if option.test is None: - option.test = TESTS - if option.buildtype is None: - option.buildtype = BUILDTYPES - return option - - -def setup_nuttx_root(nuttx_root): - # Step 1 - fs.maybe_make_directory(nuttx_root) - fs.chdir(nuttx_root) - if not fs.exists('nuttx'): - ex.check_run_cmd('git', ['clone', - 'https://bitbucket.org/nuttx/nuttx.git']) - fs.chdir('nuttx') - ex.check_run_cmd('git', ['checkout', NUTTXTAG]) - fs.chdir('..') - - if not fs.exists('apps'): - ex.check_run_cmd('git', ['clone', - 'https://bitbucket.org/nuttx/apps.git']) - fs.chdir('apps') - ex.check_run_cmd('git', ['checkout', NUTTXTAG]) - fs.chdir('..') - - # Step 2 - fs.maybe_make_directory(fs.join(nuttx_root, 'apps', 'system', 'iotjs')) - for file in fs.listdir(fs.join(path.PROJECT_ROOT, - 'config', 'nuttx', 'stm32f4dis','app')): - fs.copy(fs.join(path.PROJECT_ROOT, 'config', - 'nuttx', 'stm32f4dis', 'app', file), - fs.join(nuttx_root, 'apps', 'system', 'iotjs')) - - # Step 3 - fs.chdir(fs.join(nuttx_root, 'nuttx', 'tools')) - ex.check_run_cmd('./configure.sh', ['stm32f4discovery/usbnsh']) - fs.chdir('..') - fs.copy(fs.join(path.PROJECT_ROOT, - 'config', - 'nuttx', - 'stm32f4dis', - '.config.travis'), - '.config') - - -def build_nuttx(nuttx_root, buildtype, maketarget): - fs.chdir(fs.join(nuttx_root, 'nuttx')) - if buildtype == "release": - rflag = 'R=1' - else: - rflag = 'R=0' - ex.check_run_cmd('make', - [maketarget, 'IOTJS_ROOT_DIR=' + path.PROJECT_ROOT, rflag]) - - -def setup_tizen_root(tizen_root): - if fs.exists(tizen_root): - fs.chdir(tizen_root) - ex.check_run_cmd('git', ['pull']) - fs.chdir(path.PROJECT_ROOT) - else: - ex.check_run_cmd('git', ['clone', - 'https://github.com/pmarcinkiew/tizen3.0_rootstrap.git', - tizen_root]) - - -def build(buildtype, args=[]): - fs.chdir(path.PROJECT_ROOT) - ex.check_run_cmd('./tools/build.py', ['--buildtype=' + buildtype] + args) - - -def get_os_dependency_exclude_module(exclude_module): - os_dependency_module = {} - all_module = set(exclude_module['all']) - for os_name in exclude_module.keys(): - if not os_name == 'all': - os_dependency_module[os_name] = \ - list(all_module | set(exclude_module[os_name])) - return os_dependency_module - - -option = parse_option() -config = get_config() -os_dependency_module = \ - get_os_dependency_exclude_module(config['module']['exclude']) - -# Excluded modules are also included in the build test. -# Travis will test all implemented modules. -for os_name in os_dependency_module: - if os_dependency_module[os_name]: - os_dependency_module[os_name] = \ - ['--iotjs-include-module=' + ','.join(os_dependency_module[os_name])] - -build_args = [] - -if option.buildoptions: - build_args.extend(option.buildoptions.split(',')) - -for test in option.test: - if test == "host-linux": - for buildtype in option.buildtype: - build(buildtype, os_dependency_module['linux'] + build_args) - - if test == "host-darwin": - for buildtype in option.buildtype: - build(buildtype, os_dependency_module['darwin'] + build_args) - - elif test == "rpi2": - for buildtype in option.buildtype: - build(buildtype, ['--target-arch=arm', '--target-board=rpi2'] - + os_dependency_module['linux'] + build_args) - - elif test == "artik10": - for buildtype in option.buildtype: - tizen_root = fs.join(path.PROJECT_ROOT, 'deps', 'tizen') - setup_tizen_root(tizen_root) - build(buildtype, ['--target-arch=arm', - '--target-os=tizen', - '--target-board=artik10', - '--compile-flag=--sysroot=' + tizen_root - ] + os_dependency_module['linux'] + build_args) - - elif test == "nuttx": - current_dir = os.getcwd() - for buildtype in option.buildtype: - nuttx_root=fs.join(path.PROJECT_ROOT, 'deps', 'nuttx') - setup_nuttx_root(nuttx_root) - build_nuttx(nuttx_root, buildtype, 'context') - build(buildtype, ['--target-arch=arm', - '--target-os=nuttx', - '--nuttx-home=' + fs.join(nuttx_root, 'nuttx'), - '--target-board=stm32f4dis', - '--jerry-heaplimit=78'] - + os_dependency_module['nuttx'] + build_args) - build_nuttx(nuttx_root, buildtype, 'all') - fs.chdir(current_dir) - - elif test == "misc": - - args = [] - if os.getenv('TRAVIS') != None: - args = ['--travis'] - ex.check_run_cmd('tools/check_signed_off.sh', args) - - if not check_tidy(path.PROJECT_ROOT): - ex.fail("Failed tidy check") - - build("debug", build_args) - build("debug", ['--no-snapshot', '--jerry-lto'] - + os_dependency_module['linux'] + build_args) - - build("debug", ['--iotjs-minimal-profile'] + build_args) - - elif test == "coverity": - build("debug", os_dependency_module['linux'] + build_args) diff --git a/tools/repl.js b/tools/repl.js new file mode 100644 index 0000000000..cc276a94ba --- /dev/null +++ b/tools/repl.js @@ -0,0 +1,115 @@ +/* Copyright 2019-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. + */ + +/** + * Minial REPL implementation. + * + * Notes: + * * Currently there is no support for multi-line code input. + * * No input history. + */ +var fs = require('fs'); +var EventEmitter = require('events').EventEmitter; +var utils = require('util'); + +function stdin() { + EventEmitter.call(this); +} + +utils.inherits(stdin, EventEmitter); + +stdin.prototype.start = function() { + var self = this; + var buffer = new Buffer(10); + + var read = function(buffer) { + /* Read from stdin(0) */ + fs.read(0, buffer, 0, buffer.length, -1, after_read); + }; + + var after_read = function(err, bytes_read, buffer) { + if (err) { + throw err; + }; + + if (bytes_read === 0) { + self.emit('end'); + } else { + self.emit('data', buffer.slice(0, bytes_read)); + if (!process._exiting) { + read(buffer); + } + } + }; + + read(buffer); +} + +stdin.prototype.readline = function(callback) { + var line_parts = []; + + this.on('data', function(data) { + line_parts.push(data); + + /* Check if the last character is a '\n' */ + var has_line_end = (data.readInt8(data.length - 1) == 0x0A); + if (has_line_end) { + callback(Buffer.concat(line_parts).toString()); + line_parts = []; + } + }); +}; + + +function REPL() { + this.input = new stdin(); + this._prompt_msg = new Buffer('> '); +}; + +REPL.prototype.print_prompt = function() { + /* Write to stdout(1) */ + fs.writeSync(1, this._prompt_msg, 0, this._prompt_msg.length); +}; + +REPL.prototype.run_code = function(line) { + var result; + try { + /* Doing indirect eval to force everything into the global object. */ + result = eval.call(undefined, line); + console.log(result); + } catch (ex) { + console.error(ex); + } +}; + +REPL.prototype.process_line = function(line) { + this.run_code(line); + this.print_prompt(); +}; + +REPL.prototype.start = function() { + /* Expose the "require" method for the global object. + * This way the "eval" call can access it correctly. + */ + global.require = require; + + this.print_prompt(); + this.input.start(); + this.input.readline(this.process_line.bind(this)); +}; + +var repl = new REPL(); +console.log('IoT.js (%s) Minimal REPL', process.version); +repl.start(); diff --git a/tools/test_runner.js b/tools/test_runner.js deleted file mode 100644 index c56c6746db..0000000000 --- a/tools/test_runner.js +++ /dev/null @@ -1,169 +0,0 @@ -/* Copyright 2016-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 testdriver = require('testdriver'); -var console_wrapper = require('common_js/module/console'); -var builtin_modules = - Object.keys(process.native_sources).concat(Object.keys(process.binding)); - -function Runner(driver) { - process._exiting = false; - - this.driver = driver; - this.test = driver.currentTest(); - this.finished = false; - if (driver.skipModule) { - this.skipModule = driver.skipModule; - this.skipModuleLength = this.skipModule.length; - } else { - this.skipModuleLength = 0; - } - if (driver.options.quiet == 'yes') { - this.console = console; - console = console_wrapper; - } - - return this; -} - -Runner.prototype.cleanup = function() { - if (this.driver.options.quiet == 'yes') { - console = this.console; - } - - this.driver = null; - this.attr = null; - if (this.timer != null) { - clearTimeout(this.timer); - this.timer = null; - } -}; - -Runner.prototype.spin = function() { - var that = this; - setTimeout(function() { - var timerOnlyAlive = !testdriver.isAliveExceptFor(that.timer); - if (timerOnlyAlive) { - timerOnlyAlive = !process._onNextTick(); - } - - if (timerOnlyAlive) { - process.exit(0); - } else { - if (!that.finished) { - that.spin(); - } - } - }, 0); -}; - -Runner.prototype.checkSkipModule = function() { - for (var i = 0; i < this.skipModuleLength; i++) { - if (this.test['name'].indexOf(this.skipModule[i]) >= 0) { - return true; - } - } - - return false; -}; - -Runner.prototype.checkSupportedModule = function() { - // Cut off the '.js' ending - var name = this.test['name'].slice(0, -3); - - // test_mod_smt -> [test, mod, smt] - // test_modsmt -> [test, modsmt] - var parts = name.split('_'); - if (parts[0] != 'test') { - // test filename does not start with 'test_' so we'll just - // assume we support it. - return true; - } - - // The second part of the array contains the module - // which is under test - var tested_module = parts[1]; - for (var i = 0; i < builtin_modules.length; i++) { - if (tested_module == builtin_modules[i]) { - return true; - } - } - - // In any other case we do not support this js file. - return false; -} - -Runner.prototype.run = function() { - if (!this.checkSupportedModule()) { - this.test.reason = 'unsupported module by iotjs build'; - this.finish('skip'); - return; - } - - var skip = this.test['skip']; - if (skip) { - if ((skip.indexOf('all') >= 0) || (skip.indexOf(this.driver.os) >= 0) - || (skip.indexOf(this.driver.stability) >= 0)) { - this.finish('skip'); - return; - } - } - - if (this.skipModuleLength && this.checkSkipModule()) { - this.test.reason = 'exclude module'; - this.finish('skip'); - return; - } - - this.timer = null; - if (this.test['timeout']) { - var timeout = this.test['timeout']; - if (timeout) { - var that = this; - this.timer = setTimeout(function () { - that.finish('timeout'); - }, timeout * 1000); - } - } - - try { - var source = this.driver.test(); - eval(source); - } catch(e) { - if (this.test['expected-failure']) { - this.finish('pass'); - } else if (this.test['uncaught']) { - throw e; - } else { - console.error(e); - this.finish('fail'); - } - } finally { - if (!this.finished) { - this.spin(); - } - } -}; - -Runner.prototype.finish = function(status) { - if (this.finished) - return; - - this.finished = true; - - this.driver.emitter.emit('nextTest', this.driver, status, this.test); -}; - -module.exports.Runner = Runner; diff --git a/tools/testrunner.py b/tools/testrunner.py new file mode 100755 index 0000000000..6e9750c1ae --- /dev/null +++ b/tools/testrunner.py @@ -0,0 +1,356 @@ +#!/usr/bin/env python + +# 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. + +from __future__ import print_function + +import argparse +import json +import multiprocessing +import os +import subprocess +import sys +import time + +try: + import queue +except ImportError: + # Backwards compatibility + import Queue as queue + + +from collections import OrderedDict +from common_py import path +from common_py.system.filesystem import FileSystem as fs +from common_py.system.executor import Executor +from common_py.system.executor import Terminal +from common_py.system.sys_platform import Platform + +# Defines the folder that will contain the coverage info. +# The path must be consistent with the measure_coverage.sh script. +JS_COVERAGE_FOLDER = fs.join(path.PROJECT_ROOT, '.coverage_output') + +# This code should be applied to each testfile. +JS_COVERAGE_CODE = ( +""" +process.on('exit', function() {{ + if (typeof __coverage__ == 'undefined') + return; + + if (typeof fs == 'undefined') + var fs = require('fs'); + + if (!fs.existsSync('{folder}')) + fs.mkdirSync('{folder}'); + + var filename = '{folder}/{file}'; + fs.writeFileSync(filename, Buffer(JSON.stringify(__coverage__))); +}}) +""" +) + +# Append coverage source to the appropriate test. +def append_coverage_code(testfile, coverage): + if not coverage: + return + + with open(testfile, 'r') as file_p: + content = file_p.read() + + with open(testfile, 'w') as file_p: + file_p.write(JS_COVERAGE_CODE.format( + folder=JS_COVERAGE_FOLDER, file=fs.basename(testfile))) + file_p.write(content) + + +# Remove coverage source from the appropriate test. +def remove_coverage_code(testfile, coverage): + if not coverage: + return + + with open(testfile, 'r') as file_p: + content = file_p.read() + index = content.find('/* Copyright') + + with open(testfile, 'w') as file_p: + file_p.write(content[index:]) + + +class Reporter(object): + @staticmethod + def message(msg="", color=Terminal.empty): + print("%s%s%s" % (color, msg, Terminal.empty)) + + @staticmethod + def report_testset(testset): + Reporter.message() + Reporter.message("Testset: %s" % testset, Terminal.blue) + + @staticmethod + def report_pass(test, time): + Reporter.message(" PASS: %s (%ss)" % (test, time), Terminal.green) + + @staticmethod + def report_fail(test, time): + Reporter.message(" FAIL: %s (%ss)" % (test, time), Terminal.red) + + @staticmethod + def report_timeout(test): + Reporter.message(" TIMEOUT: %s" % test, Terminal.red) + + @staticmethod + def report_skip(test, reason): + skip_message = " SKIP: %s" % test + + if reason: + skip_message += " (Reason: %s)" % reason + + Reporter.message(skip_message, Terminal.yellow) + + @staticmethod + def report_configuration(testrunner): + Reporter.message() + Reporter.message("Test configuration:") + Reporter.message(" iotjs: %s" % testrunner.iotjs) + Reporter.message(" quiet: %s" % testrunner.quiet) + Reporter.message(" timeout: %d sec" % testrunner.timeout) + Reporter.message(" valgrind: %s" % testrunner.valgrind) + Reporter.message(" skip-modules: %s" % testrunner.skip_modules) + + @staticmethod + def report_final(results): + Reporter.message() + Reporter.message("Finished with all tests:", Terminal.blue) + Reporter.message(" PASS: %d" % results["pass"], Terminal.green) + Reporter.message(" FAIL: %d" % results["fail"], Terminal.red) + Reporter.message(" TIMEOUT: %d" % results["timeout"], Terminal.red) + Reporter.message(" SKIP: %d" % results["skip"], Terminal.yellow) + + +class TestRunner(object): + def __init__(self, options): + self._process_pool = multiprocessing.Pool(processes=1) + self.iotjs = fs.abspath(options.iotjs) + self.quiet = options.quiet + self.platform = options.platform + self.timeout = options.timeout + self.valgrind = options.valgrind + self.coverage = options.coverage + self.skip_modules = [] + self.results = {} + self._msg_queue = multiprocessing.Queue(1) + + if options.skip_modules: + self.skip_modules = options.skip_modules.split(",") + + # Process the iotjs build information. + iotjs_output = Executor.check_run_cmd_output(self.iotjs, + [path.BUILD_INFO_PATH]) + build_info = json.loads(iotjs_output) + + self.builtins = set(build_info["builtins"]) + self.features = set(build_info["features"]) + self.stability = build_info["stability"] + self.debug = build_info["debug"] + self.arch = build_info["arch"] + if "napi" in self.builtins: + self.build_napi_test_module() + + def build_napi_test_module(self): + node_gyp = fs.join(path.PROJECT_ROOT, + 'node_modules', + '.bin', + 'node-gyp') + + print('==> Build N-API test module with node-gyp\n') + + project_root = fs.join(path.PROJECT_ROOT, 'test', 'napi') + cmd = ['--debug'] if self.debug else ['--release'] + if self.platform == 'windows': + node_gyp += '.cmd' + cmd.append('--arch=x64' if self.arch == 'x64' else '--arch=ia32') + Executor.check_run_cmd(node_gyp, ['rebuild'] + cmd, + cwd=project_root) + + def run(self): + Reporter.report_configuration(self) + + self.results = { + "pass": 0, + "fail": 0, + "skip": 0, + "timeout": 0 + } + + with open(fs.join(path.TEST_ROOT, "testsets.json")) as testsets_file: + testsets = json.load(testsets_file, object_pairs_hook=OrderedDict) + + for testset, tests in testsets.items(): + self.run_testset(testset, tests) + + Reporter.report_final(self.results) + + def run_testset(self, testset, tests): + Reporter.report_testset(testset) + + for test in tests: + testfile = fs.join(path.TEST_ROOT, testset, test["name"]) + timeout = test.get("timeout", self.timeout) + + if self.skip_test(test): + Reporter.report_skip(test["name"], test.get("reason")) + self.results["skip"] += 1 + continue + + append_coverage_code(testfile, self.coverage) + + exitcode, output, runtime = self.run_test(testfile, timeout) + expected_failure = test.get("expected-failure", False) + + remove_coverage_code(testfile, self.coverage) + + # Timeout happened. + if exitcode == -1: + Reporter.report_timeout(test["name"]) + self.results["timeout"] += 1 + continue + + # Show the output. + if not self.quiet and output: + print(output.decode("utf8"), end="") + + is_normal_run = (not expected_failure and exitcode == 0) + is_expected_fail = (expected_failure and exitcode in [1, 2]) + if is_normal_run or is_expected_fail: + Reporter.report_pass(test["name"], runtime) + self.results["pass"] += 1 + else: + Reporter.report_fail(test["name"], runtime) + self.results["fail"] += 1 + + def run_test(self, testfile, timeout): + command = [self.iotjs, testfile] + + if self.valgrind: + valgrind_options = [ + "--leak-check=full", + "--error-exitcode=5", + "--undef-value-errors=no" + ] + + command = ["valgrind"] + valgrind_options + command + + try: + process = multiprocessing.Process(target=run_subprocess, + args=(self._msg_queue, command)) + start = time.time() + process.start() + process.join(timeout) + runtime = round((time.time() - start), 2) + + if process.is_alive(): + raise multiprocessing.TimeoutError("Test still running") + + # At this point the queue must have data! + # If not then it is also a timeout event + exitcode, stdout = self._msg_queue.get_nowait() + + except (multiprocessing.TimeoutError, queue.Full): + process.terminate() + return -1, None, None + + return exitcode, stdout, runtime + + def skip_test(self, test): + skip_list = set(test.get("skip", [])) + + # Skip by the `skip` attribute in testsets.json file. + for i in ["all", self.platform, self.stability]: + if i in skip_list: + return True + + required_modules = set(test.get("required-modules", [])) + required_features = set(test.get("required-features", [])) + + unsupported_modules = required_modules - self.builtins + unsupported_features = required_features - self.features + skipped_modules = required_modules.intersection(skip_list) + + # Skip the test if the tested module requires a module + # which is not compiled into the binary + if unsupported_modules: + test["reason"] = "Required module(s) unsupported by iotjs build: " + test["reason"] += ', '.join(sorted(unsupported_modules)) + return True + + # Skip the test if it requires a module that is skipped by the + # testrunner + if skipped_modules: + test["reason"] = "Required module(s) skipped by testrunner: " + test["reason"] += ', '.join(sorted(skipped_modules)) + return True + + # Skip the test if it uses features which are + # unavailable in the current iotjs build + if unsupported_features: + test["reason"] = "Required feature(s) unsupported by iotjs build: " + test["reason"] += ', '.join(sorted(unsupported_features)) + return True + + return False + + +def run_subprocess(parent_queue, command): + process = subprocess.Popen(args=command, + cwd=path.TEST_ROOT, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + + stdout = process.communicate()[0] + exitcode = process.returncode + + parent_queue.put_nowait([exitcode, stdout]) + +def get_args(): + parser = argparse.ArgumentParser() + + parser.add_argument("iotjs", action="store", + help="path to the iotjs binary file") + parser.add_argument('--platform', default=Platform().os(), + help='Specify the platform (default: %(default)s)') + parser.add_argument("--quiet", action="store_true", default=False, + help="show or hide the output of the tests") + parser.add_argument("--skip-modules", action="store", metavar='list', + help="module list to skip test of specific modules") + parser.add_argument("--timeout", action="store", default=300, type=int, + help="default timeout for the tests in seconds") + parser.add_argument("--valgrind", action="store_true", default=False, + help="check tests with Valgrind") + parser.add_argument("--coverage", action="store_true", default=False, + help="measure JavaScript coverage") + + return parser.parse_args() + + +def main(): + options = get_args() + + testrunner = TestRunner(options) + testrunner.run() + if testrunner.results["fail"]: + sys.exit(1) + +if __name__ == "__main__": + main() diff --git a/tools/travis_script.py b/tools/travis_script.py new file mode 100755 index 0000000000..6f71115358 --- /dev/null +++ b/tools/travis_script.py @@ -0,0 +1,286 @@ +#!/usr/bin/env python + +# 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. + +import os + +from common_py.system.filesystem import FileSystem as fs +from common_py.system.executor import Executor as ex +from common_py.system.sys_platform import Platform +from check_tidy import check_tidy + +platform = Platform() + +DOCKER_ROOT_PATH = fs.join('/root') + +# IoT.js path in travis +TRAVIS_BUILD_PATH = fs.join(os.environ['TRAVIS_BUILD_DIR']) + +# IoT.js path in docker +DOCKER_IOTJS_PATH = fs.join(DOCKER_ROOT_PATH, 'work_space/iotjs') + +# Node server path in docker +DOCKER_NODE_SERVER_PATH = fs.join(DOCKER_ROOT_PATH, 'work_space/node_server') + +DOCKER_TIZENRT_PATH = fs.join(DOCKER_ROOT_PATH, 'TizenRT') +DOCKER_TIZENRT_OS_PATH = fs.join(DOCKER_TIZENRT_PATH, 'os') +DOCKER_TIZENRT_OS_TOOLS_PATH = fs.join(DOCKER_TIZENRT_OS_PATH, 'tools') + +DOCKER_NUTTX_PATH = fs.join(DOCKER_ROOT_PATH, 'nuttx') +DOCKER_NUTTX_TOOLS_PATH = fs.join(DOCKER_NUTTX_PATH, 'tools') +DOCKER_NUTTX_APPS_PATH = fs.join(DOCKER_ROOT_PATH, 'apps') + +DOCKER_NAME = 'iotjs_docker' +DOCKER_TAG = 'iotjs/ubuntu:0.10' +BUILDTYPES = ['debug', 'release'] +TIZENRT_TAG = '2.0_Public_M2' + +# Common buildoptions for sanitizer jobs. +BUILDOPTIONS_SANITIZER = [ + '--buildtype=debug', + '--clean', + '--compile-flag=-fno-common', + '--compile-flag=-fno-omit-frame-pointer', + '--jerry-cmake-param=-DJERRY_SYSTEM_ALLOCATOR=ON', + '--no-check-valgrind', + '--no-snapshot', + '--profile=test/profiles/host-linux.profile', + '--run-test=full', + '--target-arch=i686' +] + +def start_container(): + run_docker() + start_mosquitto_server() + start_node_server() + +def run_docker(): + ex.check_run_cmd('docker', ['pull', DOCKER_TAG]) + ex.check_run_cmd('docker', ['run', '-dit', '--privileged', + '--name', DOCKER_NAME, '-v', + '%s:%s' % (TRAVIS_BUILD_PATH, DOCKER_IOTJS_PATH), + '--add-host', 'test.mosquitto.org:127.0.0.1', + '--add-host', 'echo.websocket.org:127.0.0.1', + '--add-host', 'httpbin.org:127.0.0.1', + DOCKER_TAG]) + +def exec_docker(cwd, cmd, env=[], is_background=False): + exec_cmd = 'cd %s && ' % cwd + ' '.join(cmd) + if is_background: + docker_args = ['exec', '-dit'] + else: + docker_args = ['exec', '-it'] + + for e in env: + docker_args.append('-e') + docker_args.append(e) + + docker_args += [DOCKER_NAME, 'bash', '-c', exec_cmd] + ex.check_run_cmd('docker', docker_args) + +def start_mosquitto_server(): + exec_docker(DOCKER_ROOT_PATH, ['mosquitto', '-d']) + +def start_node_server(): + exec_docker(DOCKER_NODE_SERVER_PATH, ['node', 'server.js'], [], True) + +def set_config_tizenrt(buildtype): + exec_docker(DOCKER_ROOT_PATH, [ + 'cp', + fs.join(DOCKER_IOTJS_PATH, + 'config/tizenrt/artik05x/configs/', + buildtype, 'defconfig'), + fs.join(DOCKER_TIZENRT_OS_PATH, '.config')]) + +def build_iotjs(buildtype, args=[], env=[]): + exec_docker(DOCKER_IOTJS_PATH, [ + './tools/build.py', + '--clean', + '--buildtype=' + buildtype] + args, env) + +JOBS = dict() + +class job(object): + def __init__(self, name): + self.name = name + def __call__(self, fn): + JOBS[self.name] = fn + +@job('host-linux') +def job_host_linux(): + start_container() + + for buildtype in BUILDTYPES: + build_iotjs(buildtype, [ + '--cmake-param=-DENABLE_MODULE_ASSERT=ON', + '--run-test=full', + '--profile=profiles/minimal.profile']) + + for buildtype in BUILDTYPES: + build_iotjs(buildtype, [ + '--run-test=full', + '--profile=test/profiles/host-linux.profile']) + +@job('n-api') +def job_n_api(): + start_container() + + # N-API should work with both ES5.1 and ES2015-subset JerryScript profiles + for buildtype in BUILDTYPES: + build_iotjs(buildtype, [ + '--run-test=full', + '--n-api']) + + for buildtype in BUILDTYPES: + build_iotjs(buildtype, [ + '--run-test=full', + '--n-api', + '--jerry-profile=es2015-subset']) + +@job('mock-linux') +def job_mock_linux(): + start_container() + for buildtype in BUILDTYPES: + build_iotjs(buildtype, [ + '--run-test=full', + '--target-os=mock', + '--profile=test/profiles/mock-linux.profile']) + +@job('rpi2') +def job_rpi2(): + start_container() + for buildtype in BUILDTYPES: + build_iotjs(buildtype, [ + '--target-arch=arm', + '--target-board=rpi2', + '--profile=test/profiles/rpi2-linux.profile']) +@job('stm32f4dis') +def job_stm32f4dis(): + start_container() + + # Copy the application files to apps/system/iotjs. + exec_docker(DOCKER_ROOT_PATH, [ + 'cp', '-r', + fs.join(DOCKER_IOTJS_PATH,'config/nuttx/stm32f4dis/app/'), + fs.join(DOCKER_NUTTX_APPS_PATH, 'system/iotjs/')]) + + exec_docker(DOCKER_ROOT_PATH, [ + 'cp', '-r', + fs.join(DOCKER_IOTJS_PATH, + 'config/nuttx/stm32f4dis/config.travis'), + fs.join(DOCKER_NUTTX_PATH, + 'configs/stm32f4discovery/usbnsh/defconfig')]) + + for buildtype in BUILDTYPES: + exec_docker(DOCKER_NUTTX_PATH, ['make', 'distclean']) + exec_docker(DOCKER_NUTTX_TOOLS_PATH, + ['./configure.sh', 'stm32f4discovery/usbnsh']) + exec_docker(DOCKER_NUTTX_PATH, ['make', 'clean']) + exec_docker(DOCKER_NUTTX_PATH, ['make', 'context']) + # Build IoT.js + build_iotjs(buildtype, [ + '--target-arch=arm', + '--target-os=nuttx', + '--nuttx-home=' + DOCKER_NUTTX_PATH, + '--target-board=stm32f4dis', + '--jerry-heaplimit=78', + '--profile=test/profiles/nuttx.profile']) + # Build Nuttx + if buildtype == "release": + rflag = 'R=1' + else: + rflag = 'R=0' + exec_docker(DOCKER_NUTTX_PATH, [ + 'make', 'all', + 'IOTJS_ROOT_DIR=' + DOCKER_IOTJS_PATH, rflag]) + +@job('tizen') +def job_tizen(): + start_container() + for buildtype in BUILDTYPES: + if buildtype == "debug": + exec_docker(DOCKER_IOTJS_PATH, [ + 'config/tizen/gbsbuild.sh', + '--debug', '--clean']) + else: + exec_docker(DOCKER_IOTJS_PATH, ['config/tizen/gbsbuild.sh', + '--clean']) + +@job('misc') +def job_misc(): + ex.check_run_cmd('tools/check_signed_off.sh', ['--travis']) + ex.check_run_cmd('tools/check_tidy.py') + +@job('external-modules') +def job_external_modules(): + start_container() + for buildtype in BUILDTYPES: + build_iotjs(buildtype, [ + '--run-test=full', + '--profile=test/profiles/host-linux.profile', + '--external-modules=test/external_modules/' + 'mymodule1,test/external_modules/mymodule2', + '--cmake-param=-DENABLE_MODULE_MYMODULE1=ON', + '--cmake-param=-DENABLE_MODULE_MYMODULE2=ON']) + +@job('es2015') +def job_es2015(): + start_container() + for buildtype in BUILDTYPES: + build_iotjs(buildtype, [ + '--run-test=full', + '--jerry-profile=es2015-subset']) + +@job('no-snapshot') +def job_no_snapshot(): + start_container() + for buildtype in BUILDTYPES: + build_iotjs(buildtype, ['--run-test=full', '--no-snapshot', + '--jerry-lto']) + +@job('host-darwin') +def job_host_darwin(): + for buildtype in BUILDTYPES: + ex.check_run_cmd('./tools/build.py', [ + '--run-test=full', + '--buildtype=' + buildtype, + '--clean', + '--profile=test/profiles/host-darwin.profile']) + +@job('asan') +def job_asan(): + start_container() + build_iotjs('debug', [ + '--compile-flag=-fsanitize=address', + '--compile-flag=-O2' + ] + BUILDOPTIONS_SANITIZER, + ['ASAN_OPTIONS=detect_stack_use_after_return=1:' + 'check_initialization_order=true:strict_init_order=true', + 'TIMEOUT=600']) + +@job('ubsan') +def job_ubsan(): + start_container() + build_iotjs('debug', [ + '--compile-flag=-fsanitize=undefined' + ] + BUILDOPTIONS_SANITIZER, + ['UBSAN_OPTIONS=print_stacktrace=1', 'TIMEOUT=600']) + +@job('coverity') +def job_coverity(): + ex.check_run_cmd('./tools/build.py', ['--clean']) + +if __name__ == '__main__': + JOBS[os.getenv('OPTS')]() diff --git a/tools/zlib-Makefile.patch b/tools/zlib-Makefile.patch deleted file mode 100644 index e2f7abf2e3..0000000000 --- a/tools/zlib-Makefile.patch +++ /dev/null @@ -1,34 +0,0 @@ ---- Makefile 2016-12-05 19:10:42.985931000 +0900 -+++ Makefile.patched 2016-12-05 19:19:14.437931000 +0900 -@@ -16,7 +16,7 @@ - # To install in $HOME instead of /usr/local, use: - # make install prefix=$HOME - --CC=gcc -+CC=arm-linux-gnueabihf-gcc - - CFLAGS=-O3 -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN - #CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 -@@ -27,8 +27,8 @@ - SFLAGS=-O3 -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN - LDFLAGS= - TEST_LDFLAGS=-L. libz.a --LDSHARED=gcc -shared -Wl,-soname,libz.so.1,--version-script,zlib.map --CPP=gcc -E -+LDSHARED=arm-linux-gnueabihf-gcc -shared -Wl,-soname,libz.so.1,--version-script,zlib.map -+CPP=arm-linux-gnueabihf-gcc -E - - STATICLIB=libz.a - SHAREDLIB=libz.so -@@ -36,9 +36,9 @@ - SHAREDLIBM=libz.so.1 - LIBS=$(STATICLIB) $(SHAREDLIBV) - --AR=ar -+AR=arm-linux-gnueabihf-ar - ARFLAGS=rc --RANLIB=ranlib -+RANLIB=arm-linux-gnueabihf-ranlib - LDCONFIG=ldconfig - LDSHAREDLIBC=-lc - TAR=tar