Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

This document guides users to perform the below activties on a Raspberry Pi (Rpi) platform as well as an Amlogic Reference platform

  1. Setup a development environment for an IPSTB target
  2. Bring up the device
  3. Create & run a sample lightning app in the device


Info
iconfalse

On this Page:

Table of Contents
maxLevel1

<work in progress>

toc



Background Color
color#F5F5F5

Before you begin

RDK is an open source code project distributed through industry standard open source licenses e.g. Apache 2.0.

Basic skills expected

Basic skills needed by a user to use the current documentation

  • Basic knowledge of Ubundu

  • Basic Build knowledge

  • Basic RDK knowledge

  • Basic knowledge of using a Raspberry Pi boxes (If trying in Raspberry Pi)

  • Basic knowledge of how to perform flashing and bring up a Raspberry Pi setup

  • Skills to connect and bring up Reference Board (If trying with Reference Board)


Basic Skills

Though not mandatory, the below skills will help the user to understand RDK, RDK build, and to try out RDK better :

  • Familiar with Linux based platforms
  • Familiar with Yocto
  • Familiar with RDK basics
  • Knowledge in using Raspberry Pi
  • Experience in setting up boards
AUI Tab Group
Relevant RDK linksbgcolorcolor
RDK SupportRDK Source CodeRDK V ReleasesAPI Documentation
FAQ Documetation
    #F5F5F5

    Build Setup Instructions

    Hardware requirements and setting up the host environment and Downloading Source Code is explained below.

    Setting up the Host Environment

    Prerequisites

    ThunderJS documentation 

    Prerequisites


    Yocto 2.2 (Morty)
    Requirement

    Requirement

    Yocto 3.1 LTS (Dunfell)

    Linux

    32/64 bit Ubuntu 16.04 LTS

    Precise supported distributions and versions are here

    PC

    64 bit Ubuntu 18.04 LTS

    Precise supported distributions and versions are here

    Free HDD SpaceMinimum 100GB Free Memory

    Minimum 100GB Free memory space

    Oracle Virtual Box

    5.0.40 or higher

    -

    Wireless Adapter

    Brand Name: Tenda ralink & Model Number:W311MI

    TP-Link Archer T4U AC 1200

    -

    USB to Ethernet Switch

    To connect with Ethernet Switch & Multiple Clients

    Host Tools version

    Git 1.8.3.1 or greater

    tar 1.24 or greater

    Python 2.7.3

    Git 1.8.3.1 or greater

    tar 1.28 or greater

    Python 3.5.0 or greater

    Install the following packages for setting up the host VM

    The instructions provided below are meant to be executed via the command line on an Ubuntu machine

    Host Tools version

    Git 1.8.3.1 or greater

    tar 1.24 or greater

    Python 2.7.3

    Raspberry Pi development kit
    IPSTB Reference boardAccess to repositories hosting code and binaries for reference board
    PeripheralsTV, Keyboard
    Background Color
    color#F5F5F5

    Environment

    Expand
    titleExpand to know the similarities and differences between RPI and IPSTB

    Rpi & IPSTB similarities:

    • Reference devices to try and run RDK
    • No need of RDK license to try out IPSTB builds


    Difference between Raspberry Pi (Rpi) and IPSTB:

    Raspberry Pi (Rpi)

    IPSTB

    Generic hobby device altered in software for STB capabilities

    Hardware specifically made for STB purpose

    Low end device capable of only mimicking STB capabilities

    Regular hardware used in real STBs

    Available in general market

    Available for licensed users of SoC vendor

    No licenses required to generate and use builds

    Agreement with IPSTB SoC vendor required to obtain software licenses (such as SDK, Kernel etc.)

    Rpi builds supported in all quarterly releases

    IPSTB builds might not be regularly supported in all quarterly releases

    Host Setup

    Install the following packages for setting up your host VM

    The instructions provided below are meant to be executed via the command line on an Ubuntu machine


    Code Block
    languagebash
    themeMidnight
    titlefor yocto 3.1 (dunfell)
    # essential packages installation
    # super user mode is required
    
    # major essential packages
    
    Code Block
    themeMidnight
    titlefor yocto 2.2 (morty)
    # essential packages installation
    # super user mode is required
     
    # major essential packages
    sudo apt-get install gawk wget git-core diffstat unzip texinfo gcc-multilib g++-multilib build-essential chrpath socat bison curl
    # supportivecpio packages
    sudopython3 aptpython3-getpip installpython3-pexpect libfile-slurp-perl libncurses-dev autoconf flex doxygen libtool automake libpcre3-dev zlib1g-dev libbz2-dev subversion minicom putty libssl-dev rpm python-pexpect python-svn python-argparse vim tofrodos meld dos2unix cmake uuid-dev ruby transfig libglib2.0-dev xutils-dev lynx-cur gperf autopoint python-dulwich python-dev openjdk-7-jre

    Note : Please note openjdk-7-jre package is not available for Ubuntu-16.04 anymore. Presumably openjdk-8-jre should be used instead.

    Code Block
    themeMidnight
    titlefor yocto 3.1 (dunfell)
    # essential packages installation
    # super user mode is required
     
    # major essential packages
    sudo apt-get install gawk wget git-core diffstat unzip texinfo gcc-multilib g++-multilib build-essential chrpath socat bison curl cpio python3 python3-pip python3-pexpect xz-utils debianutils iputils-ping python3-git python3-jinja2 libegl1-mesa libsdl1.2-dev pylint3 xterm
    
    

    Configure bash as default command interpreter for shell scripts

    Code Block
    themeMidnight
    sudo dpkg-reconfigure dash

    Select “No”
    To choose bash, when the prompt asks if you want to use dash as the default system shell - select “No”

    Configure Git

    Upgrade your Git version to 1.8.x or higher

    On Ubuntu 16.04 LTS, if you are unable to upgrade your git version using apt-get, then follow the below steps in order to upgrade 

    Code Block
    themeMidnight
    sudo apt-get install python-software-properties
    sudo add-apt-repository ppa:git-core/ppa
    sudo apt-get update
    sudo apt-get install git

    Once git is installed, configure your name and email using the below commands

    Code Block
    # review your existing configuration
    git config --list --show-origin
     
    # configure user name and email address
    git config --global user.name "John Doe"
    git config --global user.email johndoe@example.com
     
    # configure git cookies. Needed for Gerrit to only contact the LDAP backend once.
    git config --global http.cookieFile /tmp/gitcookie.txt
    git config --global http.saveCookies true

    Configure repo

    In order to use Yocto build system, first you need to make sure that repo is properly installed on the machine:

    Code Block
    themeMidnight
    # create a bin directory
    mkdir ~/bin
    export PATH=~/bin:$PATH
     
    # Download the repo tool and ensure that it is executable
    curl http://commondatastorage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
    chmod a+x ~/bin/repo

    Trivia Repo is a repository management tool that is built on top of Git. Its main purpose is to help manage projects that consist of many Git repositories, it can also be used to manage uploads to the CMF Gerrit instance and automate aspects of the development workflow.

    Repo does not replace Git, it simply aids management of projects that contain multiple Git repositories into a single local working directory. Git will still be used for local operation such as commits etc.

    Repo manages this for you by means of an XML based Manifest file. The Manifest file defines which repositories the project uses and links to appropriate revisions of each git repository, i.e where the upstream repositories reside and where they should be cloned locally. It is the manifest.xml (or default.xml) that determines which Git repositories and revisions repo will manage. This manifest.xml file is hosted in a Git repository along with all the other git repositories.

    Credential configuration

    Note: it is also recommended to put credentials in .netrc when interacting with the repo.

    A sample .netrc file is illustrated below

    machine code.rdkcentral.com

        login <YOUR_USERNAME>

        password <YOUR_PASSWORD>

    Downloading Source Code & Building

    Downloading Source Code

    Following commands fetch the source code using repo tool

    $ mkdir <Directory-Name> && cd <Directory-Name>

    Please use the following repo init command

    $ repo init -u https://user@code.rdkcentral.com/r/manifests -m manifest.xml -b <branch_name>

    Examples :

    repo init -u https://code.rdkcentral.com/r/manifests -m rdkb.xml -b rdkb-20180527

    repo init -u https://code.rdkcentral.com/r/manifests -m rdkb.xml -b master

    repo init -u https://code.rdkcentral.com/r/manifests -m rdkb.xml -b morty

    $ repo sync -j`nproc` --no-clone-bundle

    Warning
    • Cloning the code before login once to code.rdkcentral.com, user would get the Authentication error, even though the account is in good standing and has all the required access.
    • Please login to code.rdkcentral.com before attempting to clone.

    Building

    $ source <setup-environment>

    The above step configures and sets up your directory to start an appropriate build.

    There are different kinds of builds listed. Please read the options and select the number of the build you need.

    1) meta-rdk-bsp-emulator/conf/machine/qemuarmbroadband.conf
    2) meta-rdk-bsp-emulator/conf/machine/qemux86broadband.conf
    3) meta-rdk-bsp-emulator/conf/machine/qemux86hyb.conf
    4) meta-rdk-bsp-emulator/conf/machine/qemux86mc.conf
    5) openembedded-core/meta/conf/machine/qemuarm.conf
    6) openembedded-core/meta/conf/machine/qemux86-64.conf
    7) openembedded-core/meta/conf/machine/qemux86.conf

    Next, you need to initiate the build using the following command:

    $ bitbake <image-name>

    On Successful build, the ROOTFS (in vmdk format) would be available at the following reference location based on the build type :

    -$ {HOME}/emulator/build-qemux86broadband/tmp/deploy/images/qemux86broadband/rdk-generic-broadband-image-qemux86broadband-<timestamp>.vmdk

    Example :  

    …/build-qemux86broadband/tmp/deploy/images/qemux86broadband/rdk-generic-broadband-image-qemux86broadband-20160217080610.vmdk

    Background Color
    color#F5F5F5

    Environment Rpi 3b+

    Host Setup

    Refer the section Setting up the Host Environment for host setup details

    Build Setup

    Code Block
    themeMidnight
    titlebuild setup
    repo init -u https://code.rdkcentral.com/r/manifests -b dunfell -m rdkv-nosrc.xml
    repo sync -j `nproc` --no-clone-bundle --no-tags

    Image Build

    Media Client

    Instruction to build media client image

    Code Block
    themeMidnight
    titleimage build
    MACHINE=raspberrypi-rdk-mc source meta-cmf-raspberrypi/setup-environment
    bitbake rdk-generic-mediaclient-wpe-image

    Hybrid Gateway

    Instruction to build hybrid gateway image

    Code Block
    themeMidnight
    titleimage build
    MACHINE=raspberrypi-rdk-hybrid source meta-cmf-raspberrypi/setup-environment
    bitbake rdk-generic-hybrid-wpe-image

    Hybrid Gateway with Operator Ref. App

    Instruction to build hybrid gateway image with operator reference application

    Code Block
    themeMidnight
    titleimage build
    MACHINE=raspberrypirdkhybrefapp source meta-cmf-raspberrypi/setup-environment
    bitbake rdk-generic-hybrid-refapp-image

    The generated image resides under the directory build-<MACHINE>/tmp/deploy/images/<MACHINE> of the Yocto workspace

    Flash Procedure

    The micro SD card should not have any partition while flashing the image. The complete memory of the card should be free

    Code Block
    themeMidnight
    # of - output file (the device file for the inserted micro SD card
    bzcat <IMAGE_NAME>-<MACHINE>.wic.bz2 | sudo dd of=/dev/sdb bs=4M iflag=fullblock oflag=direct conv=fsync

    Known Issue

    • Cobalt is crashed upon launching over RDK Shell
    Background Color
    color#F5F5F5

    Environment  IPSTB ref box

    Same as RPI-above section and this can combine and can be made one.

    Background Color
    color#F5F5F5

    Build basic image for Rpi

    Yocto Build Setup

    All RPi based RDK images with the latest features are from the rdk-next branch

    Initializing the Build Environment

    To build RDK images from ipstb_bringup branch, follow the below build procedure

    Code Block
    themeMidnight
    titleGeneric build
    mkdir workspace
    cd workspace
     
    # initialize the manifest with repo tool
    repo init -u https://code.rdkcentral.com/r/rdkcmf/manifests -b rdkv-2021q3 -m rdkv-extsrc.xml
    repo sync  -j `nproc` --no-clone-bundle --no-tags

    Image build

    Code Block
    themeMidnight
    titleGeneric image
    MACHINE=raspberrypi-rdk-ipmc source meta-cmf-raspberrypi/setup-environment
     
    bitbake rdk-generic-ipclient-image

    Flashing Procedure

    The image file will be generated under build-<MACHINE>/tmp/deploy/images/<MACHINE> directory.

    eg: dsrava434@dvm-yocto3-docker-dsrava434:~/varsha/build-raspberrypi-rdk-ipmc/tmp/deploy/images/raspberrypi-rdk-ipmc$ pwd

    /home/dsrava434/varsha/build-raspberrypi-rdk-ipmc/tmp/deploy/images/raspberrypi-rdk-ipmc

    dsrava434@dvm-yocto3-docker-dsrava434:~/varsha/build-raspberrypi-rdk-ipmc/tmp/deploy/images/raspberrypi-rdk-ipmc$ ls -lrt rdk-generic-ip-stb-client_rdk-next_20210913112356.rootfs.wic.bz2

    -rw-r--r-- 2 dsrava434 dsrava434 141959535 Sep 13 12:33 rdk-generic-ip-stb-client_rdk-next_20210913112356.rootfs.wic.bz2

    dsrava434@dvm-yocto3-docker-dsrava434:~/varsha/build-raspberrypi-rdk-ipmc/tmp/deploy/images/raspberrypi-rdk-ipmc$ 

    Code Block
    themeMidnight
    # Insert the micro SD card to the host system and mention the card's device file name
    # input file (if) is the image file to flash and the output file (of) is the card's device file name
    bzcat <image name> | sudo dd of=/dev/<sd file> bs=4M iflag=fullblock oflag=direct conv=fsync

    System View

    Image Removed

    Testing Procedure

    •  For connecting Controller UI, use URL: http://<machineip>:9998

    Image Removed

    • Pluggins can be enabled or disabled from controller UI. 

    Image Removed

    • Wifi related services can be triggered from Wi-Fi tab in controller UI. We can scan and select from available networks.

    Image Removed

    • For ssh, we can use ssh root@machineip
    • For verifying the image details, we can use cat /version.txt command.    

    root@raspberrypi-rdk-ipmc:~# cat /version.txt 

    imagename:rdk-generic-ip-stb-client_rdk-next_20210902101930

    BRANCH=rdk-next

    YOCTO_VERSION=dunfell

    VERSION=4.09.02.21

    SPIN=0

    BUILD_TIME="2021-09-02 10:19:30"

    Generated on Thu Sep 02  10:19:30 UTC 2021

    root@raspberrypi-rdk-ipmc:~# 

    • For playing a video using aamp-cli, launch aamp-cli from terminal, cd /usr/bin;aamp-cli.

    Image Removed

    •  For playing a video using gstreamer, use gst-launch-1.0.

      eg :- gst-launch-1.0 playbin uri=aamp://bitdash-a.akamaihd.net/content/MI201109210084_1/m3u8s/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.m3u8 video-sink=westerossink

    Known Issues

    S. No

    Issues

    Status

    Remarks

    S. No

    Issues

    Status

    Remarks

    1Unable to pair bluetooth remote via resident appopenBT via controller UI is working as expected2Wifi connections are unsuccessful via resident appOpenWifi via controller Ui is working as expected3Playback using aamp-cli is not working as expectedopenplayback is successful, but screen is visible only if we disable residentapp service.4Board reboot every 30 minutesopen

    As work around, comment out On failure from dsmgr.service.

    Path : /lib/systemd/system/dsmgr.service

    Comment out " OnFailure=reboot-notifier@%i.service"

    Jira Ticket: Image RemovedREFPLTV-1099 - Rebooting observed in RPi3 device in IPSTB image IN PROGRESS

    5CNN application taking to more time to load the application.Sometimes device rebooted when we try to play any content.OpenSimilar behavior is observed in dunfell branch6Vimeo application taking to more time to load the application.Sometimes device rebooted when we try to play any content. OpenSimilar behavior is observed in dunfell branch

    Trouble Shooting

    •        If the wireless networks are not listed in controller wifi page, try after disabling and enabling wifi from Network page, networks will be listed.
    •        Disable cntlm-main.service if device reboot occasionally.
    Background Color
    color#F5F5F5

    Build basic image IPSTB ref box

    Code checkout:

    Code Block
    themeMidnight
    $ mkdir <RDK_DIR>
    $ cd <RDK_DIR>
    $ repo init -u https://code.rdkcentral.com/r/collaboration/soc/amlogic/aml-accel-manifests -b rdk-next -m rdk-firebolt-dunfell-ref-sc2-k54-202109.xml 
    $ repo sync -j4 --no-clone-bundle
     
    or
     
    $ repo init -u https://code.rdkcentral.com/r/collaboration/soc/amlogic/aml-accel-manifests -b rdk-next -m rdk-firebolt-dunfell-ref-sc2-k54-202109.xml --repo-branch=v2.9
    $ repo sync -j4 --no-clone-bundle

    Build image:

    $ cd $(RDK_DIR)
    $ export LOCAL_BUILD=1
    $ source meta-amlogic/aml-setenv.sh
     
    You're building on Linux
    Lunch menu...pick a combo:
     
    1.      mesons4-lib32-ap222
    2.      mesons4-lib32-ap223
    3.      mesons4-lib32-ap229
    4.      mesons4-lib32-aq222
    5.      mesons4-lib32-aq223
    6.      mesonsc2-5.4-lib32-ah212
    7.      mesonsc2-5.4-lib32-ah212-hybrid
    8.      mesonsc2-5.4-lib32-ah212-vmx
    9.      mesonsc2-5.4-lib32-ah219
    10.     mesonsc2-5.4-lib32-ah232
    11.     mesonsc2-5.4-lib32-ah232-irdeto
    12.     mesonsc2-5.4-lib32-ah232-nagra
    13.     mesonsc2-5.4-lib32-ah232-synamedia
     
    Which would you like? [2] 4
     
    $ bitbake lib32-rdk-generic-mediaclient-image

    Other way:

    Code Block
    themeMidnight
    $ repo init --no-clone-bundle -u https://code.rdkcentral.com/r/collaboration/oem/skyworth/skyworth-aml905X2-manifests -b rdk-next -m sc2-rdkservices-restricted.xml --repo-branch=v2.9
    $ repo sync -j 32
    $ source meta-rdk-skyworth-hx4x/setup-environment --hp44h-rdk --restricted --read-write
    $ bitbake lib32-skyworth-generic-mediaclient-image
    Background Color
    color#F5F5F5

    Flash image and bring up Rpi

    Background Color
    color#F5F5F5

    Flash image and bring up IPSTB ref box

    1) Using Burning tool
    Keep pressing enter to stop at sc2_hp44h# 
    Connect the usb-usb connector and launch Aml_Burn_Tool V3. 
    sc2_hp44# run update
    Burning tool should show connected. Select image and flash.
    2) MfrUtils
    Download the image to /data/ path on the device.
    mfrUtil -u /data/aml_upgrade_package.img
    3) Using firmware update plugin.
    Please refer to Firmware Control plugin methods to flash through thunder plugin.
    4) USB upgrade
    Copy the aml_sdc_burn.ini and image to USB. 
    Connect USB to the device and stop the device at the boot prompt. ie sc2_hp44h#
    usb_burn aml_sdc_burn.ini
    NOTE: Please reach out to Skyworth for aml_sdc_burn.ini

    Flashing through xconf :

    https://wiki.rdkcentral.com/display/RDK/Firmware+Upgrade+through+XCONF+Server

    ToDo: Alanyse what to add from the above link

    Background Color
    color#F5F5F5

    Yocto recipe structure of relevant components - wpeframework and RDKservices

    Background Color
    color#F5F5F5

    Setup and Develop Thunder plugin

    Steps involved in implementing new RDK services Plug-In

    Introduction

    RDK components implemented as Thunder plugins are called as RDKServices. it is  developed based on the Thunder (WPE) Framework. Services each other or a particular service can be COMRPC ( for (communication between plugins) or RPC (for external communication). it has a web-based controller UI.

    Reference : https://github.com/rdkcentral/rdkservices/pull/960 

     In RDK services -plugins workspace:

     Cloned from https://github.com/rdkcentral/rdkservices

    	$ git clone https://github.com/rdkcentral/rdkservices
    

    Inside PluginName directory

    1.  <PluginName>.json : This file contains the plugin's information like schema, information and interface json file.
      1. PluginTemplate.json
      2. DeviceInfo.json
    2.  CmakeLists.txt:  CMAKE based configuration file which contains a set of directives and instructions describing the project's source files and targets. This is used to compile the Plug-in code to generate the plugin library(Shared library by default; “.so”). External dependencies can be included/linked to the target with the help of CMakeLists.txt configurations.
    3. Module.h: This header file includes the support for JSON request, response, logging etc...
    4. Module.cpp: This file is used to declare the module name for the Plug-in. This file contains the plugin's information like schema, information and interface json file (defined earlier).
    5. <PluginName>.config: This file is used to set configurations of the Plug-in . Ex:- set (autostart true) - Used to make the Plug-in to start automatically along with wpeframework daemon
    6. <PluginName>.h :Declare the plugin class in this which should contains all the structures, variables and methods which are needed for plugin implementation. The interface header auto-generated earlier will be used here,
    7. <PluginName>.cpp: This class does contains all the definitions for the methods declared in the Plugin.h and those definitions should be defined inside the below namespace.
    8. Cmake / (directory) :
        

    PluginTemplate/
      ├── CMakeLists.txt
      ├── PluginTemplate.config
      ├── PluginTemplate.cpp
      ├── PluginTemplate.h
      ├── PluginTemplate.json
      ├── Module.cpp
      ├── Module.h
      ├── README.md
      ├── cmake
      |   ├── FindDS.cmake
      │   └── FindIARMBus.cmake
      └── doc
       └── PluginTemplate.md

    <PluginName>.json

     This file contains the plugin's information like schema, information and interface json file.

    Syntax :

    Code Block
    themeConfluence
       {
        {
        "$schema": "plugin.schema.json",
        "info": {
        "title": "Plugin Name Plugin",
        "callsign": "PluginName",
        "locator": "libWPEFrameworkPluginName.so",
        "status": "production",
        "description": "The PluginName plugin allows retrieving of various plugin-related information.",
        "version": "1.0"
         },
         "interface": {
        "$ref": "{interfacedir}/PluginName.json#"
         }
       }

    eg: PluginTemplate.json

    Code Block
    themeConfluence
     {
         "locator":"libWPEFrameworkPluginTemplate.so",
         "classname":"PluginTemplate",
         "precondition":[
          "Platform"
         ],
         "callsign":"org.rdk.PluginTemplate",
         "autostart":false
     } 
    <PluginName>.config

    .config files are files used to configure the parameters and initial settings for some computer programs.

    Code Block
    languagecpp
    themeConfluence
    set (autostart false)                       #we are setting autostart condition disable 
    set (preconditions Platform) 
    set (callsign "org.rdk.PluginTemplate") 	#The callsign name was given to an instance of a plugin. 
    
    #One plugin can be instantiated multiple times. but each instance, the instance-name "callsign" must be unique. here we using org.rdk.PluginTemplate. 

    <PluginName>.h

    Declare the plugin class in this which should contain all the structures, variables, and methods which are needed for plugin implementation. 

    Code Block
    languagecpp
    themeConfluence
     namespace WPEFramework {
      namespace Plugin {
       
       class PluginName : public PluginHost::IPlugin, public PluginHost::IWeb, public PluginHost::JSONRPC {
       public:
         PluginName()
          : _skipURL(0)
          , _service(nullptr)
          , _subSystem(nullptr)
         {
          RegisterAll();
         }
      
         virtual ~PluginName()
         {
          UnregisterAll();
         }
       }
       ---------------------------------------
       ---------------------------------------
      }
    }

    eg: PluginTemplate.h

    for more information refer PluginTemplate.h 

    <PluginName>.cpp

    This class does contain all the definitions for the methods declared in the PluginTemplate.h and those definitions should be defined inside the below namespace. 

    The plugin should register using service registration MACRO as declared below :

    Code Block
    languagecpp
    themeConfluence
      namespace WPEFramework {
       namespace Plugin {  
        SERVICE_REGISTRATION(Plugin, 1, 0);
        ---------------------------------------
        ---------------------------------------
        ---------------------------------------
       }
      }

     To initialize and deinitialize or activate or deactivate handler for the plugin services :

    Code Block
    languagecpp
    themeConfluence
    const string PluginTemplate::Initialize(PluginHost::IShell* /* service */)
    	{
    	//shared pointer initialized
    	//initialize external library
            LOGINFO();
            return (string());
            }
    void PluginTemplate::Deinitialize(PluginHost::IShell* /* service */)
            {
     	//shared pointer deinitialized
    	//deinitialize external library
            LOGINFO();
            }

    eg:

    Code Block
    languagecpp
    themeConfluence
    namespace WPEFramework {
        namespace Plugin {  
             SERVICE_REGISTRATION(Plugin, 1, 0);
                    
              //registration
              //All the methods declared in Plugin.h should be registered here
                    
              //initialize and deinitialize the handlers for the plug-in service
                    
              //All the methods declared in Plugin.h should be defined here
                                  
        }
    } 

    CMakeLists.txt

    Using the CMake utility this file contains the task needed to be done to make a plug-in. Also contains packages, libraries needed to compile, its path, and other plugin-in configuration option.

    This file contains a set of directives and instructions describing the project's source files and targets (executable, library, or both).

    Code Block
    languagecpp
    themeConfluence
    set(PLUGIN_NAME PluginTemplate)                          # to set a environment variable set(<variable> <value>)
    set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME})
    find_package(${NAMESPACE}Plugins REQUIRED)               # to Finds and loads settings from an external project.
    
    #Adds a library target called <name> to be built from the source files listed in the command invocation. The <name> corresponds to the logical target name and must be globally unique within a project.
    add_library(${MODULE_NAME} SHARED
            PluginTemplate.cpp
            Module.cpp
            ../helpers/utils.cpp)

    Code flow

    • Enable or disable the plug-in flag in the recipe file.
    • Add this flag into the main CMakeLists.txt file present in the rdkservice.
    • It will invoke CMakeLists file present in the <plugin name>/ (eg: PluginTemplate/CMakeLists.txt).
    • When this file started to execute it finds dependencies, packages. it compiled and generate .so file.

    To add plugin in rdkservices CMakeLists.txt

    In rdkservices directory open CmakeLists.txt :

    	$ vi CmakeLists.txt
    

    add these lines ( by default its disabled ) :

    Code Block
    themeConfluence
        if(PLUGIN_PLUGINTEMPLATE)
        	add_subdirectory(PluginTemplate)
        endif()

     it will invoke your CMakeLists.txt file present in your plugin directory.

    Compilation and Install

    To include plugintemplate plugin in build sequence, Open rdkservices recipe file and add below line. By default; its configured to be disabled while building rdkservices.

                $ vi meta-rdk-video/recipes-extended/rdkservices/rdkservices_git.bb
    
    Code Block
    themeConfluence
    PACKAGECONFIG[plugintemplate]      = " -DPLUGIN_PLUGINTEMPLATE=OFF,-DPLUGIN_PLUGINTEMPLATE=ON, "  

    To include the plugin in rdkservises build; add the same in packageconfig in rdkservices recipe:

                  PACKAGECONFIG += " plugintemplate"

    to compile and install in build directory :

    	$ bitbake -c compile -f rdkservices
    

    once build complete copy .json, .so file into raspberrypi.

    Copy the Plugin.json (eg: PluginTemplate.json) file to “/etc/WPEFramework/plugins” in raspberrypi

              Copy the plugin library (libWPEFrameworkPluginTemplate.so) to “/usr/lib/wpeframework/plugins”

    so that the controller plugin identify it and list it in the WebUI ( controller UI ).

    Controller UI

    Controller UI is a web UI that can be launched from a host machine's (machine under the same network where RPi resides) browser. This UI can be loaded with the RPi box's IP address with Thunder's port number configured (here). RDKServices uses 9998 as port.

    URL: http://<Rpi's IP address>:9998

    Defalut page of Controller UI shall be loaded on web-browser and that will be of Controller tab. Controller tab allows all available plugins to be enabled or disabled.

    Image Removed

    PluginTemplate JSON RPC command

    Each RDK Service can be validated through JSON RPC Commands through HTTP. It has a request and response in JSN format.

    Note: the argument is case sensitive.

    "callsign":"org.rdk.PluginTemplate"

    FunctionRequestResponseRemarksActivate controllercurl http://localhost:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{ "jsonrpc":"2.0", "id":3, "method":"Controller.1.activate", "params":{"callsign":"org.rdk.PluginTemplate"} }' 
     {"jsonrpc":"2.0","id":3,"result":{"success":true}}Deactivate controllercurl http://localhost:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{ "jsonrpc":"2.0", "id":3, "method":"Controller.1.deactivate", "params":{"callsign":"org.rdk.PluginTemplate"} }' 
     {"jsonrpc":"2.0","id":3,"result":{"success":true}}getPluginStatuscurl http://127.0.0.1:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.PluginTemplate.1.getPluginTemplateStatus"}'
     {"jsonrpc":"2.0","id":3,"result":{"connection status from plugin":["CONNECTED"],"success":true}}getPluginTemplateListcurl http://127.0.0.1:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.PluginTemplate.1.getPluginTemplateList"}'
     {"jsonrpc":"2.0","id":3,"result":{"Supported plugin list":["plug-A","plug-B","plug-C","plug-D","plug-E"],"success":true}}getPluginTemplateInfocurl http://127.0.0.1:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.PluginTemplate.1.getPluginTemplateInfo", "params":{"plugin_name":"plug-A"}}'
     {"jsonrpc":"2.0","id":3,"result":{"supportedTvResolutions":["xyz-plugin","no:430HT5"],"success":true}}root@raspberrypi-rdk-mc:~#
    xz-utils debianutils iputils-ping python3-git python3-jinja2 libegl1-mesa libsdl1.2-dev pylint3 xterm

    Configure bash as default command interpreter for shell scripts


    Code Block
    languagebash
    themeMidnight
    sudo dpkg-reconfigure dash

    Select “No”
    To choose bash, when the prompt asks if you want to use dash as the default system shell - select “No”

    Configure Git

    Upgrade your Git version to 1.8.x or higher

    Once git is installed, configure your name and email using the below commands

    Code Block
    languagebash
    themeMidnight
    # review your existing configuration
    git config --list --show-origin
    
    # configure user name and email address
    git config --global user.name "John Doe"
    git config --global user.email johndoe@example.com
    
    # configure git cookies. Needed for Gerrit to only contact the LDAP backend once.
    git config --global http.cookieFile /tmp/gitcookie.txt
    git config --global http.saveCookies true

    Configure repo

    In order to use Yocto build system, first you need to make sure that repo is properly installed on the machine:

    Code Block
    languagebash
    themeMidnight
    # create a bin directory
    mkdir ~/bin
    export PATH=~/bin:$PATH
    
    # Download the repo tool and ensure that it is executable
    curl http://commondatastorage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
    chmod a+x ~/bin/repo

     Credential configuration (Only for Amlogic reference board)

    Note: it is also recommended to put credentials in .netrc when interacting with the repo.

    A sample .netrc file is illustrated below

    machine code.rdkcentral.com

        login <YOUR_USERNAME>

        password <YOUR_PASSWORD>

    Background Color
    color#F5F5F5

    Build

    AUI Tab Group
    Build basic image for RpiMidnight

    The generated image resides under the directory build-<MACHINE>/tmp/deploy/images/<MACHINE> of the Yocto workspace


    Build basic image for Amlogic Reference Board

    Enabled the distro(ipclient) for IPSTB as a setup environment option, so during build time we can pass this as an argument.

    Midnight

    The generated image resides under the directory build-<MACHINE>/tmp/deploy/images/<MACHINE> of the Yocto workspace


    Background Color
    color#F5F5F5

    Flash image and bring up

    AUI Tab Group
    Flash image and bring up Rpi 

    Flash image

    1. Insert an SD card in the SD card port of the USB SD card reader (or Laptop).

         Prefer to use 32gb sd card and there should be minimum 12gb free space available in the device .

    2. Verify that the SD card has been detected by executing either of the commands listed below

    MidnightMidnight

     3. Type the following command to ensure that the partitions, if present, on the SD card are not mounted

    MidnightMidnight


    4. Repeat the below command to unmount all the mounted partition present on the SD card.

    MidnightMidnight

    5. Execute the following command to flash the image on the SD card

    MidnightFlash Command

    6. Remove the SD card and insert it to the Raspberry Pi SD card slot 

    7. Power on the Rpi and Bring up the device



    • TV screen will display the Raspberry Pi's IP address(referred as machineIP from now) with default RDK UI as shown below.


    Accessing Raspberry Pi

    •  For connecting Controller UI, use URL: http://<machineIP>:9998

    • Plugins can be enabled or disabled from controller UI. 

    • Wifi related services can be triggered from Wi-Fi tab in controller UI. We can scan and select from available networks.

    • For ssh, we can use ssh root@machineip
    • For verifying the image details, we can use cat /version.txt command. 
    Midnight
    • For playing a video using aamp-cli, launch aamp-cli from terminal, cd /usr/bin;aamp-cli.
    Midnight


    •  For playing a video using gstreamer, use gst-launch-1.0.

      eg :- gst-launch-1.0 playbin uri=aamp://bitdash-a.akamaihd.net/content/MI201109210084_1/m3u8s/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.m3u8 video-sink=westerossink

    Midnight
    Flash image and bring Amlogic Reference Platform

    Flash image

    There are multiple methods to flash/upgrade image in an Amlogic reference board. For the ease of process, we will use the USB based method, which is easy as well as helps to recover even the devices that went into a bad state. The method is as simple as copying a configuration file and the image to flash in a USB and restart the device and run a command

    1. Copy the below text to a file called aml_sdc_burn.ini 

      pyMidnight
    2. Edit the aml_sdc_burn.ini file and add the image name in it against the key 'package'. In the example, the name 'aml_upgrade_package.img' is used

      pyMidnight
    3. Copy the ini file and image name to a USB
    4. Plug the USB to reference board. Reboot the device. Press Ctrl+C via UART until the bootloader prompt comes as shown below

      pyMidnight
    5. Give the command 'usb_burn aml_sdc_burn.ini' in the terminal. Wait for the flashing to complete

    6. Reboot the device upon prompted so. Wait for the device to come up


    There are other image upgrade methods also available. Please refer to https://wiki.rdkcentral.com/display/RDK/Build+and+Flashing+Steps for more details

    Accessing Amlogic STB

    • Controller UI : For connecting Controller UI, use URL: http://<machineip>:9998

    • WiFi Service

    • Bluetooth Service

    • DRM:

     aamp-cli https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel-dash-playready.ism/.mpd
     aamp-cli https://wowzaec2demo.streamlock.net/live/bigbuckbunny-enc-wv.stream/manifest_mvlist.mpd



    Background Color
    color#F5F5F5

    Yocto recipe structure of relevant components

    Below is the major meta-layers specific to Raspberry Pi.

    Raspberry Pi major meta-layers structure:

    draw.io Diagram
    bordertrue
    diagramNameRpi recipe structure
    simpleViewerfalse
    width
    linksauto
    tbstyletop
    lboxtrue
    diagramWidth1070
    revision5


    Below is the major meta-layers specific to Amlogic IPSTB

    Amlogic major meta-layers structure:


    draw.io Diagram
    bordertrue
    diagramNameAmlogic recipe strcuture
    simpleViewerfalse
    width
    linksauto
    tbstyletop
    lboxtrue
    diagramWidth1072
    revision4



    Background Color
    color#F5F5F5

    Setup and Develop Thunder plugin


    Steps involved in implementing new RDK services Plug-In

    RDK components implemented as Thunder plugins are called as RDKServices. it is  developed based on the Thunder (WPE) Framework. Services each other or a particular service can be COMRPC for (communication between plugins) or JSONRPC (for external communication). It has a web-based controller UI.

    Reference : https://github.com/rdkcentral/rdkservices/pull/960 

     In RDK services -plugins workspace:

     Cloned from https://github.com/rdkcentral/rdkservices

    	$ git clone https://github.com/rdkcentral/rdkservices
    

    Inside PluginName directory

    1.  <PluginName>.json : This file contains the plugin's information like schema, information and interface json file.
      1. PluginTemplate.json
    2.  CmakeLists.txt:  CMAKE based configuration file which contains a set of directives and instructions describing the project's source files and targets. This is used to compile the Plug-in code to generate the plugin library(Shared library by default; “.so”). External dependencies can be included/linked to the target with the help of CMakeLists.txt configurations.
    3. Module.h: This header file includes the support for JSON request, response, logging etc...
    4. Module.cpp: This file is used to declare the module name for the Plug-in. This file contains the plugin's information like schema, information and interface json file (defined earlier).
    5. <PluginName>.config: This file is used to set configurations of the Plug-in . Ex:- set (autostart true) - Used to make the Plug-in to start automatically along with wpeframework daemon
    6. <PluginName>.h :Declare the plugin class in this which should contains all the structures, variables and methods which are needed for plugin implementation. The interface header auto-generated earlier will be used here,
    7. <PluginName>.cpp: This class does contains all the definitions for the methods declared in the Plugin.h and those definitions should be defined inside the below namespace.
    8. Cmake / (directory) :
        

    PluginTemplate/
      ├── CMakeLists.txt
      ├── PluginTemplate.config
      ├── PluginTemplate.cpp
      ├── PluginTemplate.h
      ├── PluginTemplate.json
      ├── Module.cpp
      ├── Module.h
      ├── README.md
      ├── cmake
      |   ├── FindDS.cmake
      │   └── FindIARMBus.cmake
      └── doc
       └── PluginTemplate.md

    <PluginName>.json

     This file contains the plugin's information like schema, information and interface json file.

    Syntax :

    Code Block
    themeMidnight
       {
        {
        "$schema": "plugin.schema.json",
        "info": {
        "title": "Plugin Name Plugin",
        "callsign": "PluginName",
        "locator": "libWPEFrameworkPluginName.so",
        "status": "production",
        "description": "The PluginName plugin allows retrieving of various plugin-related information.",
        "version": "1.0"
         },
         "interface": {
        "$ref": "{interfacedir}/PluginName.json#"
         }
       }

    eg: PluginTemplate.json

    Code Block
    themeMidnight
     {
         "locator":"libWPEFrameworkPluginTemplate.so",
         "classname":"PluginTemplate",
         "precondition":[
          "Platform"
         ],
         "callsign":"org.rdk.PluginTemplate",
         "autostart":false
     } 

    <PluginName>.config

    .config files are files used to configure the parameters and initial settings for some computer programs.

    Code Block
    languagecpp
    themeMidnight
    set (autostart false)                       #we are setting autostart condition disable 
    set (preconditions Platform) 
    set (callsign "org.rdk.PluginTemplate") 	#The callsign name was given to an instance of a plugin. 
    
    #One plugin can be instantiated multiple times. but each instance, the instance-name "callsign" must be unique. here we using org.rdk.PluginTemplate. 

    <PluginName>.h

    Declare the plugin class in this which should contain all the structures, variables, and methods which are needed for plugin implementation. 

    Code Block
    languagecpp
    themeMidnight
     namespace WPEFramework {
      namespace Plugin {
       
       class PluginName : public PluginHost::IPlugin, public PluginHost::IWeb, public PluginHost::JSONRPC {
       public:
         PluginName()
          : _skipURL(0)
          , _service(nullptr)
          , _subSystem(nullptr)
         {
          RegisterAll();
         }
      
         virtual ~PluginName()
         {
          UnregisterAll();
         }
       }
       ---------------------------------------
       ---------------------------------------
      }
    }

    eg: PluginTemplate.h

    for more information refer PluginTemplate.h 

    <PluginName>.cpp

    This class does contain all the definitions for the methods declared in the PluginTemplate.h and those definitions should be defined inside the below namespace. 

    The plugin should register using service registration MACRO as declared below :

    Code Block
    languagecpp
    themeMidnight
      namespace WPEFramework {
       namespace Plugin {  
        SERVICE_REGISTRATION(Plugin, 1, 0);
        ---------------------------------------
        ---------------------------------------
        ---------------------------------------
       }
      }

     To initialize and deinitialize or activate or deactivate handler for the plugin services :

    Code Block
    languagecpp
    themeMidnight
    const string PluginTemplate::Initialize(PluginHost::IShell* /* service */)
    	{
    	//shared pointer initialized
    	//initialize external library
            LOGINFO();
            return (string());
            }
    void PluginTemplate::Deinitialize(PluginHost::IShell* /* service */)
            {
     	//shared pointer deinitialized
    	//deinitialize external library
            LOGINFO();
            }

    eg:

    Code Block
    languagecpp
    themeMidnight
    namespace WPEFramework {
        namespace Plugin {  
             SERVICE_REGISTRATION(Plugin, 1, 0);
                    
              //registration
              //All the methods declared in Plugin.h should be registered here
                    
              //initialize and deinitialize the handlers for the plug-in service
                    
              //All the methods declared in Plugin.h should be defined here
                                  
        }
    } 

    CMakeLists.txt

    Using the CMake utility this file contains the task needed to be done to make a plug-in. Also contains packages, libraries needed to compile, its path, and other plugin-in configuration option.

    This file contains a set of directives and instructions describing the project's source files and targets (executable, library, or both).

    Code Block
    languagecpp
    themeMidnight
    set(PLUGIN_NAME PluginTemplate)                          # to set a environment variable set(<variable> <value>)
    set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME})
    find_package(${NAMESPACE}Plugins REQUIRED)               # to Finds and loads settings from an external project.
    
    #Adds a library target called <name> to be built from the source files listed in the command invocation. The <name> corresponds to the logical target name and must be globally unique within a project.
    add_library(${MODULE_NAME} SHARED
            PluginTemplate.cpp
            Module.cpp
            ../helpers/utils.cpp)

    Code flow

    • Enable or disable the plug-in flag in the recipe file.
    • Add this flag into the main CMakeLists.txt file present in the rdkservice.
    • It will invoke CMakeLists file present in the <plugin name>/ (eg: PluginTemplate/CMakeLists.txt).
    • When this file started to execute it finds dependencies, packages. it compiled and generate .so file.

    To add plugin in rdkservices CMakeLists.txt

    In rdkservices directory open CmakeLists.txt :

    	$ vi CmakeLists.txt
    

    add these lines ( by default its disabled ) :

    Code Block
    themeMidnight
        if(PLUGIN_PLUGINTEMPLATE)
        	add_subdirectory(PluginTemplate)
        endif()

     it will invoke your CMakeLists.txt file present in your plugin directory.

    Compilation and Install

    To include plugintemplate plugin in build sequence, Open rdkservices recipe file and add below line. By default; its configured to be disabled while building rdkservices.

                $ vi meta-rdk-video/recipes-extended/rdkservices/rdkservices_git.bb
    
    Code Block
    themeMidnight
    PACKAGECONFIG[plugintemplate]      = " -DPLUGIN_PLUGINTEMPLATE=OFF,-DPLUGIN_PLUGINTEMPLATE=ON, "  

    To include the plugin in rdkservises build; add the same in packageconfig in rdkservices recipe:

                  PACKAGECONFIG += " plugintemplate"

    to compile and install in build directory :

    	$ bitbake -c compile -f rdkservices
    

    once build complete copy .json, .so file into raspberry Pi.

    Copy the Plugin.json (eg: PluginTemplate.json) file to “/etc/WPEFramework/plugins” in raspberry Pi

              Copy the plugin library (libWPEFrameworkPluginTemplate.so) to “/usr/lib/wpeframework/plugins”

    so that the controller plugin identify it and list it in the WebUI ( controller UI ).

    Controller UI

    Controller UI is a web UI that can be launched from a host machine's (machine under the same network where Rpi resides) browser. This UI can be loaded with the Rpi box's IP address with Thunder's port number configured (here). RDKServices uses 9998 as port.


    URL: http://<IP address of the Target device>:9998


    Defalut page of Controller UI shall be loaded on web-browser and that will be of Controller tab. Controller tab allows all available plugins to be enabled or disabled.


    Image Added

    PluginTemplate JSON RPC command

    Each RDK Service can be validated through JSON RPC Commands through HTTP. It has a request and response in JSN format.

    Note: the argument is case sensitive.

    "callsign":"org.rdk.PluginTemplate"


    FunctionRequestResponseRemarks
    Activate controllercurl http://127.0.0.1:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{ "jsonrpc":"2.0", "id":3, "method":"Controller.1.activate", "params":{"callsign":"org.rdk.PluginTemplate"} }' 
     
    {"jsonrpc":"2.0","id":3,"result":{"success":true}}
    Deactivate controllercurl http://127.0.0.1:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{ "jsonrpc":"2.0", "id":3, "method":"Controller.1.deactivate", "params":{"callsign":"org.rdk.PluginTemplate"} }' 
     
    {"jsonrpc":"2.0","id":3,"result":{"success":true}}
    getPluginStatuscurl http://127.0.0.1:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.PluginTemplate.1.getPluginTemplateStatus"}'
     
    {"jsonrpc":"2.0","id":3,"result":{"connection status from plugin":["CONNECTED"],"success":true}}
    getPluginTemplateListcurl http://127.0.0.1:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.PluginTemplate.1.getPluginTemplateList"}'
     
    {"jsonrpc":"2.0","id":3,"result":{"Supported plugin list":["plug-A","plug-B","plug-C","plug-D","plug-E"],"success":true}}
    getPluginTemplateInfocurl http://127.0.0.1:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.PluginTemplate.1.getPluginTemplateInfo", "params":{"plugin_name":"plug-A"}}'
     
    {"jsonrpc":"2.0","id":3,"result":{"supportedTvResolutions":["xyz-plugin","no:430HT5"],"success":true}}root@raspberrypi-rdk-mc:~#
     event API when hdmi connected curl http://127.0.0.1:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.PluginTemplate.1.getConnectedVideoDisplays"}'
     
     {"jsonrpc":"2.0","id":3,"result":{"connectedVideoDisplays":["HDMI0"],"success":true}}root@raspberrypi-rdk-mc:~#
     event API when hdmi not connected curl http://127.0.0.1:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.PluginTemplate.1.getConnectedVideoDisplays"}'
     
     {"jsonrpc":"2.0","id":3,"result":{"connectedVideoDisplays":[],"success":true}}root@raspberrypi-rdk-mc:~#
    Code Block
    languagebash
    themeMidnight
    root@raspberrypi-rdk-mc:~# curl http://127.0.0.1:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{ "jsonrpc":"2.0", "id":3, "method":"Controller.1.activate", "params":{"callsign":"org.rdk.PluginTemplate"} }' 
    {"jsonrpc":"2.0","id":3,"result":{"success":true}}root@raspberrypi-rdk-mc:~#
    root@raspberrypi-rdk-mc:~#
    root@raspberrypi-rdk-mc:~# curl http://127.0.0.1:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{ "jsonrpc":"2.0", "id":3, "method":"Controller.1.deactivate", "params":{"callsign":"org.rdk.PluginTemplate"} }' 
    {"jsonrpc":"2.0","id":3,"result":{"success":true}}root@raspberrypi-rdk-mc:~#
    root@raspberrypi-rdk-mc:~#
    root@raspberrypi-rdk-mc:~# curl http://127.0.0.1:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.PluginTemplate.1.getPluginTemplateStatus"}'
    {"jsonrpc":"2.0","id":3,"result":{"connection status from plugin":["CONNECTED"],"success":true}}root@raspberrypi-rdk-mc:~#
    root@raspberrypi-rdk-mc:~#
    root@raspberrypi-rdk-mc:~# curl http://127.0.0.1:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.PluginTemplate.1.getPluginTemplateList"}'
    {"jsonrpc":"2.0","id":3,"result":{"Supported plugin list":["plug-A","plug-B","plug-C","plug-D","plug-E"],"success":true}}root@raspberrypi-rdk-mc:~#
    root@raspberrypi-rdk-mc:~#
    root@raspberrypi-rdk-mc:~# curl http://127.0.0.1:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.PluginTemplate.1.getPluginTemplateInfo", "params":{"plugin_name":"plug-A"}}'
    {"jsonrpc":"2.0","id":3,"result":{"supportedTvResolutions":["xyz-plugin","no:430HT5"],"success":true}}root@raspberrypi-rdk-mc:~#
    root@raspberrypi-rdk-mc:~#
    root@raspberrypi-rdk-mc:~# curl http://127.0.0.1:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.PluginTemplate.1.getConnectedVideoDisplays"}'
    {"jsonrpc":"2.0","id":3,"result":{"connectedVideoDisplays":["HDMI0"],"success":true}}root@raspberrypi-rdk-mc:~#
    root@raspberrypi-rdk-mc:~#
    root@raspberrypi-rdk-mc:~# curl http://127.0.0.1:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.PluginTemplate.1.getConnectedVideoDisplays"}'
    {"jsonrpc":"2.0","id":3,"result":{"connectedVideoDisplays":[],"success":true}}root@raspberrypi-rdk-mc:~#
    root@raspberrypi-rdk-mc:~#


    OUT OF PROCESS Plugin

    Here the plugin is developed as out of process, which runs as a separate thread from WPEFramework. Services each other or a particular service can be COMRPC ( for communication between plugins) or JSONRPC (for external communication). it has a web-based controller UI.

    Inside PluginName directory

    OutOfProcessPlugin/
      ├── CMakeLists.txt
      ├── OutOfProcessPlugin.config
      ├── OutOfProcessPlugin.cpp
      ├── OutOfProcessPlugin.h

      ├── OutOfProcessPluginJsonRpc.cpp
      ├── OutOfProcessPlugin.json
      ├── Module.cpp
      ├── Module.h
      ├── OutOfProcessPlugin.md


    <PluginName>.json

     This file contains the plugin's information like schema, information and interface json file. Here the outofprocess will be true, which indicates that the plugin run as a seperate process.

     eg: OutOfProcessPlugin.json

    Code Block
    themeMidnight
    {
    
     "locator":"libWPEFrameworkOutOfProcessPlugin.so",
    
     "classname":"OutOfProcessPlugin",
    
     "precondition":[
    
      "Platform"
    
     ],
    
     "autostart":true,
    
     "configuration":{
    
      "root":{
    
       "outofprocess":true
    
      }
    
     }
    
    }


    <PluginName>.config

    .config files are files used to configure the parameters and initial settings for some computer programs.

    Here outofprocess is set to true, to make plugin as out of process plugin.

    Code Block
    themeMidnight
    set (autostart true)
    
    set (preconditions Platform)
    
    map()
    
        kv(outofprocess true)
    
    end()
    
    ans(rootobject)


    <PluginName>.h

    Declare the plugin class in this which should contain all the structures, variables, and methods which are needed for plugin implementation. 

    Code Block
    themeMidnight
     namespace WPEFramework {
    
      namespace Plugin {
    
       class PluginName : public PluginHost::IPlugin, public PluginHost::IWeb, public PluginHost::JSONRPC {
    
       public:
    
         PluginName()
    
          : _skipURL(0)
    
          , _service(nullptr)
    
          , _subSystem(nullptr)
    
         {
    
          RegisterAll();
    
         }
    
         virtual ~PluginName()
    
         {
    
          UnregisterAll();
    
         }
    
       }
    
       ---------------------------------------
    
       ---------------------------------------
    
      }
    
    }


    <PluginName>.cpp

    This class does contain all the definitions for the methods declared in the Plugin.h and those definitions should be defined inside the below namespace. 

    The plugin should register using service registration MACRO as declared below :

    Code Block
    themeMidnight
     namespace WPEFramework {
    
       namespace Plugin { 
    
        SERVICE_REGISTRATION(Plugin, 1, 0);
    
        ---------------------------------------
    
        ---------------------------------------
    
        ---------------------------------------
    
       }
    
      }


    To initialize and deinitialize or activate or deactivate handler for the plugin services :




    Code Block
    themeMidnight
    const string OutOfProcessPlugin::Initialize(PluginHost::IShell* /* service */)
    
        {
    
        //shared pointer initialized
    
        //initialize external library
    
            LOGINFO();
    
            return (string());
    
            }
    
    void OutOfProcessPlugin::Deinitialize(PluginHost::IShell* /* service */)
    
            {
    
        //shared pointer deinitialized
    
        //deinitialize external library
    
            LOGINFO();
    
            }


    Process handler plugin services to receive request and sent responses based on the services :

    Code Block
    themeMidnight
    Core::ProxyType<Web::Response> OutOfProcessPlugin::Process(const Web::Request &request)
    
    {
    
      Core::ProxyType<Web::Response> result(PluginHost::IFactories::Instance().Response());
    
    
    
    
      //Handle the service request and send the responses
    
      -----------------
    
      -----------------
    
      return result;
    
    }


    eg: refer OutOfProcessPlugin.cpp


    <PluginNameJsonRpc>.cpp>

    The PluginNameJsonRpc file contains the registration for methods and properties which are declared in PluginName.h

    Code Block
    themeMidnight
    namespace WPEFramework {
    
        namespace Plugin {  
    
              //registration
    
             void OutOfProcessPlugin::RegisterAll()
    
              {
    
                   // methods and properties declared in Plugin.h are registered here
    
                      -------------------
    
                      ------------------- 
    
              }
    
             void OutOfProcessPlugin::UnregisterAll()
    
             {
    
             }                        
    
        }
    
    } 


    CMakeLists.txt

    Using the CMake utility this file contains the task needed to be done to make a plug-in. Also contains packages, libraries needed to compile, its path, and other plugin-in configuration option.

    This file contains a set of directives and instructions describing the project's source files and targets (executable, library, or both).

    Code Block
    themeMidnight
    set(PLUGIN_NAME OutOfProcessPlugin)                          # to set a environment variable set(<variable> <value>)
    
    set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME})
    
    find_package(${NAMESPACE}Plugins REQUIRED)               # to Finds and loads settings from an external project.
    
    
    
    
    #Adds a library target called <name> to be built from the source files listed in the command invocation. The <name> corresponds to the logical target name and must be globally unique within a project.
    
    add_library(${MODULE_NAME} SHARED
    
        OutOfProcessPlugin.cpp
    
        OutOfProcessPluginJsonRpc.cpp
    
        Module.cpp)


    The Code flow, Compilation and Install steps are similar to the PluginTemplate.

    The last step,

    Copy the Plugin.json (eg: OutOfProcessPlugin .json) file to “/etc/WPEFramework/plugins” in Raspberry Pi

              Copy the plugin library (libWPEFrameworkOutOfProcessPlugin.so) to “/usr/lib/wpeframework/plugins”

    so that the controller plugin identify it and list it in the WebUI ( controller UI ).

    Controller UI

    Controller UI is a web UI that can be launched from a host machine's (machine under the same network where Rpi resides) browser.

    URL: http://<IP address of the Target device>:9998

    Image Added

    OutOfProcessPlugin JSON RPC command

    Each RDK Service can be validated through JSON RPC Commands through HTTP. It has a request and response in JSON format.

    Note: the argument is case sensitive.

    "callsign":"OutOfProcessPlugin"


    FunctionRequestResponseRemarks
    Activate controllercurl http://127.0.0.1:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{ "jsonrpc":"2.0", "id":3, "method":"Controller.1.activate", "params":{"callsign":"OutOfProcessPlugin"} }' 
     
    {"jsonrpc":"2.0","id":3,"result":{"success":true}}
    Deactivate controllercurl http://127.0.0.1:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{ "jsonrpc":"2.0", "id":3, "method":"Controller.1.deactivate", "params":{"callsign":"OutOfProcessPlugin"} }' 
     
    {"jsonrpc":"2.0","id":3,"result":{"success":true}}
    Get fpscurl http://127.0.0.1:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"OutOfProcessPlugin.1.fps"}'
     
    {"jsonrpc":"2.0","id":3,"result":32}
    Get plugin idcurl http://127.0.0.1:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"OutOfProcessPlugin.1.getpluginid"}'
     
    {"jsonrpc":"2.0","id":3,"result":6501}
    Background Color
    color#F5F5F5

    Interface with other RDK services


    RDK components implemented as Thunder plugins are called as RDKServices. It is developed based on the Thunder (WPE) Framework. Services each other or a particular service can be COMRPC ( for communication between plugins) or JSONRPC (for external communication).i.e.

    COMRPC is used to communicate between the plugins (out of process) or to communicate for larger data.

    JSONRPC is used to fetch/update info to or from plugins externally (most of the plugins provide this in interface, similar to ReST API) also it can be used from applications.


    JSONRPC:

    For instance please see below Bluetooth plugin's pair method with JSONRPC interface.

    Events

    EventDescription
    BluetoothState: PAIRING_CHANGETriggers onStatusChanged event when the device gets paired to given device ID.
    BluetoothState: PAIRING_FAILEDTriggers onRequestFailed event, when the device is unable to pair.


    Parameters

    NameTypeDescription
    paramsobject
    params.deviceIDstringID that is derived from the Bluetooth MAC address. 6 byte MAC value is packed into 8 byte with leading zeros for first 2 bytes


    Result

    NameTypeDescription
    resultobject
    result.successbooleanWhether the request succeeded
    Code Block
    themeMidnight
    titleRequest
    {
        "jsonrpc": "2.0",
        "id": 42,
        "method": "org.rdk.Bluetooth.1.pair",
        "params": {
            "deviceID": "61579454946360"
        }
    }
    Code Block
    themeMidnight
    titleResponse
    {
        "jsonrpc": "2.0",
        "id": 42,
        "result": {
            "success": true
        }
    }

    For more details please refer : https://github.com/rdkcentral/rdkservices/blob/sprint/2107/Bluetooth/doc/BluetoothPlugin.md#pair-method


    The corresponding implementation in ThunderJS is given below:


    Code Block
    themeMidnight
       this.thunderJS.call('org.rdk.Bluetooth', 'pair', { deviceID: deviceIDval },
     
          (err, result) => {
     
            if (err) {
     
              Log.info('\n Bluetooth Pair error' + JSON.stringify(err))
     
            } else {
     
              Log.info('Pairing success' + JSON.stringify(result))
     
            }
     
          }
     
        )

    To know more about how to implement JSONRPC inerface using ThunderJS in JS environment please see https://github.com/rdkcentral/ThunderJS/blob/master/readme.md



    Background Color
    color#F5F5F5

    Interface with Lightning apps


    ThunderJS is used to make easy to make API calls to Thunder (WPEframework) over a Websocket connection. ThunderJS can also be used to listen to (and act upon) notifications broadcasted by Thunder. ThunderJS is an isomorphic library, which means it can be used in a browser environment as well as a NodeJS environment.

    Lightning is a Javascript TV app development framework based on NodeJS environment. So ThunderJS can be easily integrated to the Lightning apps.

    Adding ThunderJS dependency to package.json


    ThunderJS dependencies can be added manually to the lightning projects by adding ‘"ThunderJS": "github:rdkcentral/ThunderJS",’ to the package.json under ‘devDependencies’ and then run ‘npm install’.

    OR

    ThunderJS can be installed into your project via NPM command. Then the package.json will be updated with the thunder dependency "npm install github:rdkcentral/ThunderJS"

    Snippet of package.json is given below .To use the ES6 syntax, we need add the Babel dependency also.

    Code Block
    themeMidnight
      }
    },
    "devDependencies": {
     "@babel/core": "^7.7.2",
     "ThunderJS": "github:rdkcentral/ThunderJS",
     "babel-eslint": "^10.0.3",
     "dashjs": "^3.1.3",
     "eslint": "^6.6.0",
     "eslint-config-prettier": "^6.7.0",
     "eslint-plugin-prettier": "3.1.1",
     "hls.js": "^0.13.2",
     "husky": "^3.1.0",
     "lint-staged": "^9.4.3"
     "prettier": "^1.19.1"
      }
    }
     event API when hdmi connected curl http://127.0.0.1:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.PluginTemplate.1.getConnectedVideoDisplays"}'
      {"jsonrpc":"2.0","id":3,"result":{"connectedVideoDisplays":["HDMI0"],"success":true}}root@raspberrypi-rdk-mc:~# event API when hdmi not connected curl http://127.0.0.1:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.PluginTemplate.1.getConnectedVideoDisplays"}'
      {"jsonrpc":"2.0","id":3,"result":{"connectedVideoDisplays":[],"success":true}}root@raspberrypi-rdk-mc:~#

    Image Removed

    OUT OF PROCESS Plugin

    Introduction

    Here the plugin is developed as out of process, which runs as a separate thread from WPEFramework. Services each other or a particular service can be COMRPC ( for communication between plugins) or JSONRPC (for external communication). it has a web-based controller UI.

    Inside PluginName directory

    OutOfProcessPlugin/
      ├── CMakeLists.txt
      ├── OutOfProcessPlugin.config
      ├── OutOfProcessPlugin.cpp
      ├── OutOfProcessPlugin.h

      ├── OutOfProcessPluginJsonRpc.cpp
      ├── OutOfProcessPlugin.json
      ├── Module.cpp
      ├── Module.h
      ├── OutOfProcessPlugin.md

    <PluginName>.json

     This file contains the plugin's information like schema, information and interface json file. Here the outofprocess will be true, which indicates that the plugin run as a seperate process.

     eg: OutOfProcessPlugin.json

    {

     "locator":"libWPEFrameworkOutOfProcessPlugin.so",

     "classname":"OutOfProcessPlugin",

     "precondition":[

      "Platform"

     ],

     "autostart":true,

     "configuration":{

      "root":{

       "outofprocess":true

      }

     }

    }

    <PluginName>.config

    .config files are files used to configure the parameters and initial settings for some computer programs.

    Here outofprocess is set to true, to make plugin as out of process plugin.

    set (autostart true)

    set (preconditions Platform)

    map()

        kv(outofprocess true)

    end()

    ans(rootobject)

    <PluginName>.h

    Declare the plugin class in this which should contain all the structures, variables, and methods which are needed for plugin implementation. 

     namespace WPEFramework {

      namespace Plugin {

       class PluginName : public PluginHost::IPlugin, public PluginHost::IWeb, public PluginHost::JSONRPC {

       public:

         PluginName()

          : _skipURL(0)

          , _service(nullptr)

          , _subSystem(nullptr)

         {

          RegisterAll();

         }

         virtual ~PluginName()

         {

          UnregisterAll();

         }

       }

       ---------------------------------------

       ---------------------------------------

      }

    }

    <PluginName>.cpp

    This class does contain all the definitions for the methods declared in the Plugin.h and those definitions should be defined inside the below namespace. 

    The plugin should register using service registration MACRO as declared below :

      namespace WPEFramework {

       namespace Plugin { 

        SERVICE_REGISTRATION(Plugin, 1, 0);

        ---------------------------------------

        ---------------------------------------

        ---------------------------------------

       }

      }

    To initialize and deinitialize or activate or deactivate handler for the plugin services :

    const string OutOfProcessPlugin::Initialize(PluginHost::IShell* /* service */)

        {

        //shared pointer initialized

        //initialize external library

            LOGINFO();

            return (string());

            }

    void OutOfProcessPlugin::Deinitialize(PluginHost::IShell* /* service */)

            {

        //shared pointer deinitialized

        //deinitialize external library

            LOGINFO();

            }

    Process handler plugin services to receive request and sent responses based on the services :

    Core::ProxyType<Web::Response> OutOfProcessPlugin::Process(const Web::Request &request)

    {

      Core::ProxyType<Web::Response> result(PluginHost::IFactories::Instance().Response());

      //Handle the service request and send the responses

      -----------------

      -----------------

      return result;

    }

    eg: refer OutOfProcessPlugin.cpp

    <PluginNameJsonRpc>.cpp>

    The PluginNameJsonRpc file contains the registration for methods and properties which are declared in PluginName.h

    namespace WPEFramework {

        namespace Plugin {  

              //registration

             void OutOfProcessPlugin::RegisterAll()

              {

                   // methods and properties declared in Plugin.h are registered here

                      -------------------

                      ------------------- 

              }

             void OutOfProcessPlugin::UnregisterAll()

             {

             }                        

        }

    CMakeLists.txt

    Using the CMake utility this file contains the task needed to be done to make a plug-in. Also contains packages, libraries needed to compile, its path, and other plugin-in configuration option.

    This file contains a set of directives and instructions describing the project's source files and targets (executable, library, or both).

    set(PLUGIN_NAME OutOfProcessPlugin)                          # to set a environment variable set(<variable> <value>)

    set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME})

    find_package(${NAMESPACE}Plugins REQUIRED)               # to Finds and loads settings from an external project.

    #Adds a library target called <name> to be built from the source files listed in the command invocation. The <name> corresponds to the logical target name and must be globally unique within a project.

    add_library(${MODULE_NAME} SHARED

        OutOfProcessPlugin.cpp

        OutOfProcessPluginJsonRpc.cpp

        Module.cpp)

    The Code flow, Compilation and Install steps are similar to the PluginTemplate.

    The last step,

    Copy the Plugin.json (eg: OutOfProcessPlugin .json) file to “/etc/WPEFramework/plugins” in raspberrypi

              Copy the plugin library (libWPEFrameworkOutOfProcessPlugin.so) to “/usr/lib/wpeframework/plugins”

    so that the controller plugin identify it and list it in the WebUI ( controller UI ).

    Controller UI

    Controller UI is a web UI that can be launched from a host machine's (machine under the same network where RPi resides) browser.

    URL: http://<Rpi's IP address>:9998

    Image Removed

    OutOfProcessPlugin JSON RPC command

    Each RDK Service can be validated through JSON RPC Commands through HTTP. It has a request and response in JSON format.

    Note: the argument is case sensitive.

    "callsign":"OutOfProcessPlugin"

    FunctionRequestResponseRemarksActivate controllercurl http://127.0.0.1:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{ "jsonrpc":"2.0", "id":3, "method":"Controller.1.activate", "params":{"callsign":"OutOfProcessPlugin"} }' 
     {"jsonrpc":"2.0","id":3,"result":{"success":true}}Deactivate controllercurl http://127.0.0.1:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{ "jsonrpc":"2.0", "id":3, "method":"Controller.1.deactivate", "params":{"callsign":"OutOfProcessPlugin"} }' 
     {"jsonrpc":"2.0","id":3,"result":{"success":true}}Get fpscurl http://127.0.0.1:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"OutOfProcessPlugin.1.fps"}'
     {"jsonrpc":"2.0","id":3,"result":32}Get plugin idcurl http://127.0.0.1:9998/jsonrpc --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"OutOfProcessPlugin.1.getpluginid"}'
     {"jsonrpc":"2.0","id":3,"result":6501}
    Background Color
    color#F5F5F5

    Interface with other RDK services

    Background Color
    color#F5F5F5

    Interface with Lightning apps

    Introduction

    ThunderJS is used to make easy to make API calls to Thunder (WPEframework) over a Websocket connection. ThunderJS can also be used to listen to (and act upon) notifications broadcasted by Thunder. ThunderJS is an isomorphic library, which means it can be used in a browser environment as well as a NodeJS environment.

    Lightning is a Javascript TV app development framework based on NodeJS environment. So ThunderJS can be easily integrated to the Lightning apps

    ThunderJS Documentation

    An elaborate ThunderJS documentation is available here - https://github.com/rdkcentral/ThunderJS

    Adding ThunderJS dependency to package.json

    ThunderJS dependencies can be added manually to the lightning projects by adding ‘"ThunderJS": "github:rdkcentral/ThunderJS",’ to the package.json under ‘devDependencies’ and then run ‘npm install’.

    OR

    ThunderJS can be installed into your project via NPM command. Then the package.json will be updated with the thunder dependency "npm install github:rdkcentral/ThunderJS"
    Snippet of package.json is given below .To use the ES6 syntax, we need add the Babel dependency also.Image Removed


    Import ThunderJS dependency in Lightning script

     

    Next you can import the ThunderJS dependency into your own script like given below.

    import ThunderJS from 'ThunderJS',


    Initializing the library

     

    The library can be initialised by passing the IP, port and other parameters mentioned below


    Code Block
    themeMidnight
    const config = {  
     host: '192.168.1.100', // defaults to localhost,  
     port: 2020, // defaults to 80  endpoint: '/api', // defaults to '/jsonrpc'  
     protocol: 'wss://', // defaults to 'ws://'  
     subprotocols: 'notification', // WebSocket sub-protocols, defaults to 'notification'
    }
     const thunderJS = ThunderJS(config)


    Example:

    Code Block
    themeMidnight
    this.config = {
    	host: '127.0.0.1'
    }
     const thunderJS = ThunderJS(config)
    Example:
    ,
    	port:'9998'
    }
    try {
    	this.thunderJS = ThunderJS(this.config)
    }	catch (err) {
    	Log.error('Error in initialising the Thunder JS' , err)
    
    


     Image Removed

    Making API Calls and read results

     

    The library supports 2 ways of making API calls, depending on your coding style preferences.

    Option 1 - Argument based

     

    AUI Tab Group
    Option 1 - Argument basedMidnightOption 2 – Object basedMidnight

    The result can be processed in two ways also

    AUI Tab Group
    Option 1 - Promise basedMidnightOption 2 - Callback basedMidnight





    Example for Argument based call for Bluetooth plugin is given below where the result is processed in callback based method

    Bluetooth plugin pair method - https://github.com/rdkcentral/rdkservices/blob/sprint/2107/Bluetooth/doc/BluetoothPlugin.md#pair-method


    Corresponding implementation in ThunderJS

    Code Block
    themeMidnight
       this.thunderJS.call('org.rdk.Bluetooth', 'pair', { deviceID: deviceIDval },
    
          (err, result) => {
    
            if (err) {
    
              Log.info('\n Bluetooth Pair error' + JSON.stringify(err))
    
            } else {
    
              Log.info('Pairing success' + JSON.stringify(result))
    
            }
    
          }
    
        )

     

    Notifications


    Thunder (WPEframework) broadcasts notifications when events ocur in the system. However it will only broadcast those events that the client has subscribed to.

    ThunderJS makes it easy to subscribe to specific events, and execute a callback-function upon every notification of each event.


    Example for notification event subscriptions is given below.


    Bluetooth onDiscovered event -  https://github.com/rdkcentral/rdkservices/blob/sprint/2107/Bluetooth/doc/BluetoothPlugin.md#ondiscovereddevice-event


    Corresponding implementation in the Lightning AppImage Removed

    Code Block
    themeMidnight
    /**
    * Event listener to listen to device discovered
    */
    this.thunderJS.on('org.rdk.Bluetooth','onDiscoveredDevice',notification =>{
    	Log.info('<<Device discovered event>>'+JSON.stringify(notification))
    })
    
    
    /**