2017年7月14日 星期五

Build Microsoft Azure SDK For OpenWrt System


      Cloud for organizing and analyzing  big data is a trend, Microsoft introduces Azure Cloud for the Internet of Things(IoT) issues. The Azure SDK, purposes to be deployed in the endpoints of IoT, brings the devices able to communicate with Azure Cloud. 
       But in the most case, the sensor nodes are very weak, porting Azure SDK to the nodes is not feasible for they even not support with TCP/IP. Hence, it is necessary there are the intermediary devices to mediate the cloud and the sensor nodes. 
      The intermediary devices, usually called "IoT gateway", may be router-based and support with the other wireless protocols (like, Zigebee, BLE, Lora ..etc). So they are essentially the data transfer stations. Besides, the gateways, compared to the sensor node, are high performance,  therefore they are able to manage the sensor nodes, and deal with some (lightweight) data processing work.

     So the typical IoT architecture is :
※ The node-gateway-cloud architectures are known as "fog computing", for the gateway is the local server actually (analogous to fog and cloud, the server is nearby or distance away). On the contrast, the laptops and smartphones are powerful and directly connect to the cloud : this scenarios are called edge computing, for it is natural to put some computing on the powerful devices, and the devices are at the edge positions from the server's view. 

    Microsoft claims the SDK is cross-platform (even the micro-controller) and easy to be ported. However, I found porting the SDK to the OpenWRT system is full of the knacks,  thus I write down this post for people encountering the same issue.


零. Create a Azure acount:

  In the Azure website, https://www.azureiotsuite.com/, you should create a Microsoft account on Azure purpose. And it is necessary to input your credit number to pass the register. While the account has been created, do not forget to look at your e-mail box for certificating.
  Once your registering has been done, create a solution as remote monitor:



While launch the solution, add a device in that, that should be custom device(physics hardware device) :

Then, you could input the device id or it be generated automatically. In here, I request it generating the id in automation.

 The screen would show the information which should be recorded for later usage:
 The id, hostname and key should be input into sdk client code.

The last action in this step is to enable the device just be created:

 
(In the screen, you could seek out the column of device properties, where is the hostname, id and key written.)


一.  Build the Azure sdk in x86 Linux natively:
   You could refer to this  Azure website.

  Check the tools have been installed :

sudo apt-get install -y git cmake build-essential curl libcurl4-openssl-dev libssl-dev uuid-dev

Git clone the azure clone code from repository:

git clone --recursive https://github.com/Azure/azure-iot-sdk-c.git

it would ensure all files would be download indeedly.

In  the azure sdk folder, create a folder for contain the built binaries and call cmake to configure the setting:


cd azure-iot-sdk-c
mkdir x86_64
cd x86_64
cmake ..
cmake --build . -- -j4 

(The last line could be simply replaced as "make -j4" )

And to the folder azure-iot-sdk-c/x86_64/serializer/samples/simplesample_mqtt, to run the binary simplesample_mqtt, which would generate fake datum and send it to the cloud:


gaiger@i5-3210M:~/azure-iot-sdk-c/x86_64/serializer/samples/simplesample_mqtt$ ./simplesample_mqtt 
Info: IoT Hub SDK for C, version 1.1.18
Error: Time:Fri Jul 14 00:18:32 2017 File:/home/gaiger/azure-iot-sdk-c/iothub_client/src/iothub_client_ll.c Func:IoTHubClient_LL_CreateFromConnectionString Line:547 Tokenizer error
Error: Time:Fri Jul 14 00:18:32 2017 File:/home/gaiger/azure-iot-sdk-c/iothub_client/src/iothub_client_ll.c Func:IoTHubClient_LL_CreateFromConnectionString Line:662 iotHubName is not found
Failed on IoTHubClient_LL_Create


The problem is very obvious that the device id, key and hostname should be written in the code.

Edit the file azure-iot-sdk-c/serializer/samples/simplesample_mqtt/simplesample_mqtt.c (NOT under the x86_64 folder),  modify the code about line 31:


/*String containing Hostname, Device Id & Device Key in the format:             */
/*  "HostName=<host_name>;DeviceId=<device_id>;SharedAccessKey=<device_key>"    */
//static const char* connectionString = "[device connection string]";
static const char* connectionString = \
                                "HostName=test-0-remote-monitor23fea.azure-devices.net;" \
                                "DeviceId=CoolingSampleDevice_2656;" \
                                "SharedAccessKey=3OuqHv7YyejvxVdsYcV2OIZSof5scZRIBnKVq61Sy6s=";

There should be no space inside the string, or the sending action would not be successful.

Rebuild (you could type make in folder azure-iot-sdk-c/x86_64/serializer/samples/simplesample_mqtt) and run again, the command line reveals :


gaiger@i5-3210M:~/azure-iot-sdk-c/x86_64/serializer/samples/simplesample_mqtt$ ./simplesample_mqtt 
Info: IoT Hub SDK for C, version 1.1.18
IoTHubClient accepted the message for delivery
Message Id: 0 Received.
Result Call Back Called! Result is: IOTHUB_CLIENT_CONFIRMATION_OK 

The data has been sent successfully.

To the cloud site, the result has been recorded:
(DO NOT forget to set "Device to View" in upright corner of Azure website as the same as the set device id !!)



If you feel awful why your record has ONE datum only but I have three, do not worry that, for I have run the binary 3 times.

Now, for easy debugging, modify the file azure-iot-sdk-c/serializer/samples/simplesample_mqtt/simplesample_mqtt.c to keep generate data per two seconds, about line 223:


     /* wait for commands */
     while (1)
     {
      IoTHubClient_LL_DoWork(iotHubClientHandle);
#if(0)
      ThreadAPI_Sleep(100);
#else
      ThreadAPI_Sleep(2*1000);
      //myWeather->DeviceId = "myFirstDevice";
      myWeather->WindSpeed = avgWindSpeed + (rand() % 4 + 2);
      myWeather->Temperature = minTemperature + (rand() % 10);
      myWeather->Humidity = minHumidity + (rand() % 20);
      printf("WindSpeed = %d, Temperature = %3.1f, Humidity = %3.1f\r\n", 
       myWeather->WindSpeed, myWeather->Temperature, myWeather->Humidity);
      {
       unsigned char* destination;
       size_t destinationSize;
       if (SERIALIZE(&destination, &destinationSize, 
         myWeather->DeviceId, myWeather->WindSpeed, 
         myWeather->Temperature, myWeather->Humidity) != CODEFIRST_OK)
       {
        (void)printf("Failed to serialize\r\n");
       }
       else
       {
        sendMessage(iotHubClientHandle, destination, destinationSize, myWeather);
        free(destination);
       }
      }
#endif
     }


Rebuild and run again, you will find the data  from client to cloud ceaselessly:

gaiger@i5-3210M:~/azure-iot-sdk-c/x86_64/serializer/samples/simplesample_mqtt$ ./simplesample_mqtt 
Info: IoT Hub SDK for C, version 1.1.18
IoTHubClient accepted the message for delivery
WindSpeed = 12, Temperature = 22.0, Humidity = 72.0
IoTHubClient accepted the message for delivery
WindSpeed = 14, Temperature = 26.0, Humidity = 71.0
IoTHubClient accepted the message for delivery
WindSpeed = 13, Temperature = 29.0, Humidity = 77.0
IoTHubClient accepted the message for delivery
WindSpeed = 13, Temperature = 26.0, Humidity = 78.0
IoTHubClient accepted the message for delivery
WindSpeed = 13, Temperature = 20.0, Humidity = 74.0
IoTHubClient accepted the message for delivery
WindSpeed = 13, Temperature = 25.0, Humidity = 61.0
IoTHubClient accepted the message for delivery
WindSpeed = 13, Temperature = 21.0, Humidity = 73.0
IoTHubClient accepted the message for delivery
WindSpeed = 15, Temperature = 22.0, Humidity = 61.0
IoTHubClient accepted the message for delivery
Message Id: 0 Received.
:


To here, the x86 based client has been done.

二. Build OpenWrt system for preparing necessary toolchain and libraries.

I adopted OpenWRT-CC. To grab the code, use git clone in terminal :


sudo apt-get install subversion build-essential git-core libncurses5-dev zlib1g-dev gawk flex quilt libssl-dev xsltproc libxml-parser-perl mercurial bzr ecj cvs unzip git wget
git clone https://github.com/domino-team/openwrt-cc.git

The first line is for download the depended libraries, the second is to download the code.

Go into the openwrt-cc folder, type below command and wait a while (for downloading the libraries for menu),  you could configure the building:

.config - OpenWrt Configuration
 ──────────────────────────────────────────────────────────────────────────────
  ┌───────────────────────── OpenWrt Configuration ─────────────────────────┐
    Arrow keys navigate the menu.  <Enter> selects submenus ---> (or empty   
    submenus ----).  Highlighted letters are hotkeys.  Pressing <Y>          
    includes, <N> excludes, <M> modularizes features.  Press <Esc><Esc> to   
    exit, <?> for Help, </> for Search.  Legend: [*] built-in  [ ]           
   ┌─────────────────────────────────────────────────────────────────────┐   
           Target System (Atheros AR7xxx/AR9xxx)  --->                     
           Subtarget (Generic)  --->                                       
           Target Profile (TP-LINK TL-WR720N)  --->                        
           Target Images  --->                                             
           Global build settings  --->                                     
           Gl.iNet package choice shortcut  --->                           
       [ ] Advanced configuration options (for developers)  ----           
       [ ] Build the OpenWrt Image Builder                                 
       [ ] Build the OpenWrt SDK                                           
       [*] Package the OpenWrt-based Toolchain                             
   └────┴(+)─────────────────────────────────────────────────────────────┘   
  ├─────────────────────────────────────────────────────────────────────────┤  
          <Select>    < Exit >    < Help >    < Save >    < Load >           
  └─────────────────────────────────────────────────────────────────────────┘  
    

This setting menu  is pretty similar with linux kernel configuration menu, actually, the linux kernel would be built in OpenWrt package indeed.

For Azure client SDK issue, the following item should be set as Built-in(star note,* ), (press space botton to switch the status):


Package the OpenWrt-based Toolchain

Base System ---> librt

Libraries ---> SSL  ---> libopenssl

Libraries ---> libcurl 

Libraries --->libuuid

And set the column, " Target Profile " as the same as your device.

For me, I select TP-LINK TL-WR720N, for my development board (bought from 淘寶Alibaba of the Celestial Empire) marking out it is this model in its setting website:


Or you could find which model is your router in the webiste of OpenWrt, or the model would be written in the sticker in the button of your router.

Final action: type make and wait the building be done:


gaiger@i5-3210M:~/openwrt-cc$ make -j8
 make[1] world
 make[2] tools/install
 make[2] package/cleanup
 make[3] -C tools/patch compile
 make[3] -C tools/sstrip compile
 make[3] -C tools/make-ext4fs compile
 make[3] -C tools/firmware-utils compile
 make[3] -C tools/flock compile
:

How much time would be consumed depending how much money you spent in your computer. For my thinkpad T430@i5-3210m, it costs about 30 minutes.
Note : If you want to cleanse the configured setting, you could type "make distclean" back to the origin.


The built package will be organized and placed in folder staging_dir:

gaiger@i5-3210M:~/openwrt-cc$ ls staging_dir/
host
target-mips_34kc_uClibc-0.9.33.2
toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2

For my building, the target-mips_34kc_uClibc-0.9.33.2 and toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2 are the folders for system and toolchain respectively.

Check if the built gcc work, in my case, it exists in folder openwrt-cc/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin/:

gaiger@i5-3210M:~/openwrt-cc$ ./staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin/mips-openwrt-linux-uclibc-gcc 
mips-openwrt-linux-uclibc-gcc: fatal error: no input files
compilation terminated.



三. Build Azure SDK for OpenWrt.

Back to the azure SDK folder, as x86, create a folder to hoard the built binary for target OpenWrt. My device is TP-LINK TL-WR720N v3@Atheros AR9330 rev 1, its CPU model is MIPS 24Kc V7.4. I name the folder as mips_24kc.
It is, create a folder named mips_24kc under azure-iot-sdk-c: ~/azure-iot-sdk-c/mips_24kc

Create a file inside the target folder(mips_24kc), the file name is mips_24kc.cmake, to configure cross-compilation information for cmake usage :



INCLUDE(CMakeForceCompiler)

SET(CMAKE_SYSTEM_NAME Linux)     # this one is important
SET(CMAKE_SYSTEM_VERSION 1)     # this one not so much

# this is the location of the amd64 toolchain targeting your device
SET(CMAKE_C_COMPILER /home/gaiger/openwrt-cc/staging_dir/toolchain-mips_24kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin/mips-openwrt-linux-uclibc-gcc)
SET(CMAKE_FIND_ROOT_PATH /home/gaiger/openwrt-cc/staging_dir/target-mips_34kc_uClibc-0.9.33.2)

# search for programs in the build host directories
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)

# for libraries and headers in the target directories
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
# system location of target device
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

All you have to do is to change the CMAKE_C_COMPILER line as the location of the cross-compiler built from OpenWrt package, and modify CMAKE_FIND_ROOT_PATH line as the path of OpenWrt the system just built. The path and location should be in IN THE FULL PATH FORM WITHOUT TILDE NOTE REPRESENTING as home

Note : one is location, another is path.


The next action is to configure :

gaiger@i5-3210M:~/azure-iot-sdk-c/mips_24kc$ cmake .. \
-DCMAKE_TOOLCHAIN_FILE=mips_24kc.cmake 

-- The C compiler identification is GNU 4.8.3
-- The CXX compiler identification is GNU 4.8.3
-- Check for working C compiler: /home/gaiger/openwrt-cc/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin/mips-openwrt-linux-uclibc-gcc
:
:
:
-- AMQP Target architecture: GENERIC
-- MQTT Target architecture: GENERIC
-- iothub architecture: GENERIC
-- Configuring done
-- Generating done
-- Build files have been written to: /home/gaiger/azure-iot-sdk-c/mips_24kc

It is time to build the libraries:

But, while you type "make", it will occur error :

gaiger@i5-3210M:~/azure-iot-sdk-c/mips_24kc$ make 
:
:
[ 18%] Built target aziotsharedutil
[ 18%] Linking C executable iot_c_utility
/home/gaiger/openwrt-cc/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/lib/gcc/mips-openwrt-linux-uclibc/4.8.3/../../../../mips-openwrt-linux-uclibc/bin/ld: cannot find -lcurl
collect2: error: ld returned 1 exit status

Optional : you could set bash variable STAGING_DIR in terminal to disable compilation warnings, but they are just complaint only.

gaiger@i5-3210M:~$ export STAGING_DIR=/home/gaiger/openwrt-cc/staging_dir


The error occurs when the binary is being built in linking stage. Open the linking description file for simplesample_mqtt, which is under the build folder azure-iot-sdk-c/mips_24kc/serializer/samples/simplesample_mqtt/CMakeFiles/simplesample_mqtt.dir/link.txt :


Note : I have organized the command for easy reading, actually that is txt file, the next line note (backslash, \) would not work in this case.

/home/gaiger/openwrt-cc/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin/mips-openwrt-linux-uclibc-gcc  \
-fPIC  -Werror   CMakeFiles/simplesample_mqtt.dir/simplesample_mqtt.c.o \
CMakeFiles/simplesample_mqtt.dir/linux/main.c.o  -o \
simplesample_mqtt \
-rdynamic \
../../../iothub_client/libiothub_client_mqtt_transport.a \
../../libserializer.a \
../../../iothub_client/libiothub_client.a \
../../../umqtt/libumqtt.a \
../../../c-utility/libaziotsharedutil.a \
-lcurl \
/home/gaiger/openwrt-cc/staging_dir/target-mips_34kc_uClibc-0.9.33.2/usr/lib/libssl.so \
/home/gaiger/openwrt-cc/staging_dir/target-mips_34kc_uClibc-0.9.33.2/usr/lib/libcrypto.so \
-lpthread -lm -lrt -luuid -Wl,
-rpath,\
/home/gaiger/openwrt-cc/staging_dir/target-mips_34kc_uClibc-0.9.33.2/usr/lib


Constrast to libssl.so and libcrypto.so in the full path form, linking libcurl and libuuid have been scribed in the abbreviation form. It is expedient method to solve the error that to modify the linking libraries in the full path form manually (it is drastic and primitive way):


/home/gaiger/openwrt-cc/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin/mips-openwrt-linux-uclibc-gcc  \
-fPIC  -Werror   CMakeFiles/simplesample_mqtt.dir/simplesample_mqtt.c.o \
CMakeFiles/simplesample_mqtt.dir/linux/main.c.o  -o \
simplesample_mqtt \
-rdynamic \
../../../iothub_client/libiothub_client_mqtt_transport.a \
../../libserializer.a \
../../../iothub_client/libiothub_client.a \
../../../umqtt/libumqtt.a \
../../../c-utility/libaziotsharedutil.a \
/home/gaiger/openwrt-cc/staging_dir/target-mips_34kc_uClibc-0.9.33.2/usr/lib/libcurl.so \
/home/gaiger/openwrt-cc/staging_dir/target-mips_34kc_uClibc-0.9.33.2/usr/lib/libssl.so \
/home/gaiger/openwrt-cc/staging_dir/target-mips_34kc_uClibc-0.9.33.2/usr/lib/libcrypto.so \
-lpthread -lm -lrt /home/gaiger/openwrt-cc/staging_dir/target-mips_34kc_uClibc-0.9.33.2/usr/lib/libuuid.so -Wl,
-rpath,\
/home/gaiger/openwrt-cc/staging_dir/target-mips_34kc_uClibc-0.9.33.2/usr/lib

And type make under the folder azure-iot-sdk-c/mips-24kc/serializer/samples/simplesample_mqtt :

gaiger@i5-3210M:~/azure-iot-sdk-c/mips-24kc/serializer/samples/simplesample_mqtt$ make
[ 18%] Built target serializer
[ 75%] Built target aziotsharedutil
[ 78%] Built target umqtt
[ 90%] Built target iothub_client_mqtt_transport
[ 93%] Built target iothub_client
[ 96%] Linking C executable simplesample_mqtt
/home/gaiger/openwrt-cc/staging_dir/target-mips_34kc_uClibc-0.9.33.2/usr/lib/libcrypto.so: warning: gethostbyname is obsolescent, use getnameinfo() instead.


The compilation has been passed.

This solution is just a work-around: manual replacement string is not a good way (but it works). The better way is to fix the CMake script, or write a bash script to darn all link.txt files automatically. 

I have prepared a script to achieve the substitution.
Create a file named dornlink.sh under path azure-iot-sdk-c/mips_24kc:

# bin/bash
#Power by Gaiger Chen 撰也垓恪, to fix azure sdk error in linking stage

echo Back up file as link.txt in the same folders

find -name link.txt -exec cp {} {}.bak -f \
#find -name link.txt -exec rm {}.bak -f \;
#find . -ipath "*link.txt" -type f  -exec cp {} {}.bak \;
#find . -ipath "*link.txt" -type f  -exec rm {}.bak \;

FOUND_LINKINK_TXT=$(find -name link.txt)

OPENWRT_LIB_PATH=""

echo "$FOUND_LINKINK_TXT" | while read LINE_CONTENT
do
 if [ -z "$OPENWRT_LIB_PATH" ]; then
  OPENWRT_LIB_PATH=$(sed -rn 's/.* (.*)\/libssl.so .*/\1/p' "$LINE_CONTENT")
  echo "$OPENWRT_LIB_PATH"
 fi

 echo fix file: "$LINE_CONTENT"
 sed -i "s|-lcurl|$OPENWRT_LIB_PATH/libcurl.so|g" "$LINE_CONTENT"
 sed -i "s|-luuid|$OPENWRT_LIB_PATH/libuuid.so|" "$LINE_CONTENT"
done # while read LINE_CONTENT


FILE_NUM=$(echo "$FOUND_LINKINK_TXT" | wc -l)
echo "$FILE_NUM" files have been fixed.

After type chmod 777 dornlink.sh, run the script then rebuild,  the linking errors should be all gone.



To here, the cross-compiling has been done.

四. Deploy the binary and libraries to the target device.

Move the built binary to the target device:


scp simplesample_mqtt root@192.168.1.251:/tmp


Run the binary in the device, there is an error that the library could not be found :

root@JoySince:/tmp# ./simplesample_mqtt 
./simplesample_mqtt: can't load library 'libcurl.so.4'

Therefore, the depended libraries should be copy to the device.


In the folder ~/openwrt-cc/staging_dir/target-mips_34kc_uClibc-0.9.33.2/usr/lib, the libraries libcurl.so.4 libssl.so.1.0.0 libcrypto.so.1.0.0 libuuid.so.1  and libmbedtls.so.9 should be copied to the device, respond to /usr/lib folder:

scp libcurl.so.4 libssl.so.1.0.0 libcrypto.so.1.0.0 libuuid.so.1  libmbedtls.so.9  root@192.168.1.251:/usr/lib



In the folder openwrt-cc/staging_dir/target-mips_34kc_uClibc-0.9.33.2/root-ar71xx/lib, the libraries libpthread.so.0 and librt.so.0 should be copied to the device:

scp libpthread.so.0 librt.so.0 root@192.168.1.251:/lib


Now, run the binary in device again:

root@JoySince:/tmp# ./simplesample_mqtt 
Info: IoT Hub SDK for C, version 1.1.18
IoTHubClient accepted the message for delivery
WindSpeed = 12, Temperature = 24.0, Humidity = 72.0
IoTHubClient accepted the message for delivery
Info: error:14090086:lib(20):func(144):reason(134)
Info: Closing tlsio from a state other than TLSIO_STATE_EXT_OPEN or TLSIO_STATE_EXT_ERROR
WindSpeed = 12, Temperature = 21.0, Humidity = 67.0
IoTHubClient accepted the message for delivery
WindSpeed = 12, Temperature = 28.0, Humidity = 62.0
IoTHubClient accepted the message for delivery
Info: Evaluated delay time 0 sec.  Retry attempt count 1

WindSpeed = 13, Temperature = 27.0, Humidity = 70.0
IoTHubClient accepted the message for delivery
Info: error:14090086:lib(20):func(144):reason(134)
Info: Closing tlsio from a state other than TLSIO_STATE_EXT_OPEN or TLSIO_STATE_EXT_ERROR

The sending data is not successful again.

It is the entity of digital certificates should be installed in the device, install it via okpg command :

root@JoySince:/tmp# opkg update && opkg install ca-certificates


After the installation done,  run the binary once :

root@JoySince:/tmp# ./simplesample_mqtt 
Info: IoT Hub SDK for C, version 1.1.18
IoTHubClient accepted the message for delivery
WindSpeed = 12, Temperature = 29.0, Humidity = 79.0
IoTHubClient accepted the message for delivery
WindSpeed = 13, Temperature = 25.0, Humidity = 60.0
IoTHubClient accepted the message for delivery
WindSpeed = 14, Temperature = 21.0, Humidity = 60.0
IoTHubClient accepted the message for delivery
WindSpeed = 13, Temperature = 23.0, Humidity = 78.0
IoTHubClient accepted the message for delivery
WindSpeed = 13, Temperature = 23.0, Humidity = 77.0
IoTHubClient accepted the message for delivery
WindSpeed = 12, Temperature = 28.0, Humidity = 63.0
IoTHubClient accepted the message for delivery
WindSpeed = 14, Temperature = 26.0, Humidity = 60.0
IoTHubClient accepted the message for delivery
WindSpeed = 13, Temperature = 23.0, Humidity = 66.0
IoTHubClient accepted the message for delivery
Message Id: 0 Received.
Result Call Back Called! Result is: IOTHUB_CLIENT_CONFIRMATION_OK 
Message Id: 1 Received.
Result Call Back Called! Result is: IOTHUB_CLIENT_CONFIRMATION_OK 
Message Id: 2 Received.
Result Call Back Called! Result is: IOTHUB_CLIENT_CONFIRMATION_OK 
Message Id: 3 Received.
Result Call Back Called! Result is: IOTHUB_CLIENT_CONFIRMATION_OK 
Message Id: 4 Received.


In the Azure site, the data sent from the OpenWrt device have been received triumphantly.



Reference :

https://github.com/Azure/azure-iot-sdk-c/blob/master/doc/SDK_cross_compile_example.md
https://github.com/Azure/azure-iot-sdk-c/issues/58
https://github.com/Azure/iot-edge/issues/119
https://forum.openwrt.org/viewtopic.php?id=26725