RAK WisCellular Part2:Connect Hologram

In the last post I briefly introduce the hardware of RAK WisCellular Arduino shield board and a simple GPS test with QNavigator. In this post I would like to show how to use WisCellular to connect and send data to the Hologram server.

##Hardware required
*WisCellular shield
*USB Cable
*Hologram global IoT SIM card

##Software required
*QNavigator 1.4 link

Register Hologram SIM card and connect the board

Before starting, please make sure that the Hologram SIM card is already activated. And then please following my last post to connect the board.

Connect your favourite operator

  • Click “AT Command” in the sidebar and input AT+COPS=? in the text field near “Send” button. Click the button and wait a short time (depending on indoor or outdoor). You may receive a feedback like this:

+COPS: (2,”Vodafone.de”,”Vodafone”,”26202″,0),(1,”Telekom.de”,”TDG”,”26201″,0),(1,”E-Plus”,”E-Plus”,”26203″,0),,(0,1,2,3,4),(0,1,2)

The WisCellular has found three operators which are embedded in brackets.

Posted in NB-IoT | Leave a comment

RAK WisCellular Part 1: Overview

What is WisCellular ?

The WisCellular is a NB-IoT Arduino shield which is a upgraded version of WisLTE with global regulatory certification. I am very luck to the one of ten Betas selected for evaluating it before launching.

Which Specifications of WisCellular ? *

  • Cellular Module – Quectel BG96
  • Cellular Network
    • 4G/LTE-M (Cat M1)
    • NB-IoT (Cat NB1)
  • Global Bands
    • EDGE/EGPRS: 850/900/1800/1900MHz
    • LTE FDD: B1/B2/B3/B4/B5/B8/B12/B13/B18/B19/B20/B26/B28
    • LTE TDD: B39 (For Cat M1 Only)
  • Data Rate
    • Cat M1: Max. 300Kbps (DL), Max. 375Kbps (UL)
    • Cat NB1: Max. 32Kbps (DL), Max. 70Kbps (UL)
    • EDGE: Max. 296Kbps (DL), Max. 236.8Kbps (UL)
    • GPRS: Max. 107Kbps (DL), Max. 85.6Kbps (UL)
  • Voice – VoLTE (Cat M1 Only)
  • SMS – Point-to-point MO and MT, SMS Cell Broadcast, Text and PDU Mode
  • GNSS (optional) – GPS
  • Peripheral Interface
    • Micro USB port
    • Arduino Headers
    • 8-pin PCM Audio Header
    • 6-pin Digital/Analog I/O Header
    • 4-pin Debug Header
    • Micro SIM Card Slot
  • LED – Red (Board power-on), Green (Cellular module power-on), and Blue (Network status)
  • Power Consumption
    Min 10uA @ Power Saving Mode (PSM) for 4G/LTE Cat M1 and Cat NB1
    Max 190mA @ 23dBm for 4G/LTE Cat M1 and 78mA @23dBm for 4G/TE Cat NB1
  • Dimensions – 68.58×53.34 mm
  • Temperature Range
    • Operating: default: -35°C ~ +75°C; extended: -40°C ~ +85°C
    • Storage: -40°C ~ +90°C
  • Standards – 3GPP E-UTRA Release 13
  • Compliance – FCC, CE, WEEE, RoHS, Japan TELEC/JATE

What are inside package?

I received a paper box with WisCellular shield, Type A to Micro B USB cable, a LTE antenna, a GPS antenna and a tape for fixing GPS antenna.

Hardware required

  • WisCellular shield
  • USB Cable
  • Hologram global IoT SIM card

Software required

  • QNavigator 1.4 link

In the first review I will not write any code or command. But we could still get a lot of information and test many functions of WisCellular . Let’s start!

Register Hologram SIM card

At first, please follow the tutorial to register your Hologram SIM card.

Install USB driver link

Download and click, continue and continue until the installation is finished.

Connect the WisCellular

  • Connect WisCellular with a Windows PC via a Type A to Micro B USB cable. Click the PWRKEY of WisCellular. After a few second you will see the green light will on and meanwhile three virtual COM ports are detected in the “Device Manager”:

    • Quectel USB AT Port – AT command port, it is the primier interface for testing;
    • Quectel USB DM Port – Diagnose port, it is used for FWupgrade and catching log;
    • Quectel USB NMEA Port – GNSS port, it is used for streaming GNSS data;
  • Open QNavigator.
  • Select UMTS/HSPA even though BG96 only supports GPRS, since I want to test GNSS function. Then click Next and Start until the main interface is shown

  • Click the serial port icon to setup parameters

  • Select the AT port shown above. The other parameters are shown below

    • Baudrate: 115200
    • DatabBits: 8
    • StopBits: 1
    • Parity: None
    • FlowCtrl: None
  • Click “Connect to module”. The QNavigator will try to talk with BG96 via AT commands. You will get a not important warning message and at the same time different kinds of information are also requested and shown.

Do you have NB-IoT service nearby ?

I think the NB-IoT service is not supported every where in Germany. We could use a simple command to test whether the base station nearby has support of NB-IoT.

  • Click “AT Command” in the sidebar and find the COPS command. Click “Send” button and wait a few seconds, BG96 will show the information of the base stations nearby. From the last number of each group, the services can be identified:
    • 0 = GSM
    • 8 = LTE Cat M1
    • 9 = LTE Cat NB1

It is easy to see, in the area where I am living, there is currently no NB-IoT service :(.QNavigator_4

GNSS test

  • Click “AT Command” in the sidebar. The system will select the right serial port for you. Then you can simply click the “Connect” button.

  • The GNSS function will be activated. After a about 1 minute the position information will be shown below.

Posted in NB-IoT | Leave a comment

[Dissecting OpenWRT] #5: netifd and WiFi

In the last post, I have briefly introduced the startup process of WiFi function in OpenWrt/LEDE system. But it is only a small part. netifd is the network managment application in OpenWrt/LEDE. We can not avoid this important component to discuss the startup process of WiFi function. Therefore in this post I will introduce the netifd and its relationship with ubus, hostapd, wpa_supplicant and other scripts.

At first a diagram below is shown to demonstrate the ubus functions registration.
Alt Text

It is noted that three objects are important here: main_object, dev_object and wireless_object. These three objects include ubus functions. For example,

static struct ubus_object main_object = {
    .name = "network",
    .type = &main_object_type,
    .methods = main_object_methods,
    .n_methods = ARRAY_SIZE(main_object_methods),

where network is the entry of service functions when ubus list typed.

static struct ubus_method main_object_methods[] = {
    { .name = "restart", .handler = netifd_handle_restart },
    { .name = "reload", .handler = netifd_handle_reload },
    UBUS_METHOD("add_host_route", netifd_add_host_route, route_policy),
    { .name = "get_proto_handlers", .handler = netifd_get_proto_handlers },
    UBUS_METHOD("add_dynamic", netifd_add_dynamic, dynamic_policy),

These functions will be shown when ubus -v list network typed, where reload is the most important function. Because it will trigger all other functions to config the WiFi.

Posted in LEDE, OpenWRT | Leave a comment

[Dissecting OpenWRT] #4: /lib/functions/network.sh

OpenWRT/LEDE has alread provided us some useful shell functions to find information from physical and logical interfaces. In this post I will show you some functions from this file.

  1. Inquire the first IP address of logical interface: network_get_ipaddr
    Create a shell script called test.sh and fill it with

. /lib/functions/network.sh

if [ "$#" -ne 1 ];then
    echo "Syntax:$0 interface"
    exit 1

network_get_ipaddr ip $1
echo $ip

you can use like this

root@OpenWrt:/# chmod a+x test.sh
root@OpenWrt:/# ./test.sh lan
  1. Inquire L3 network device: network_get_device

. /lib/functions/network.sh

if [ "$#" -ne 1 ];then
    echo "Syntax:$0 interface"
    exit 1

network_get_device ifname $1
echo $ifname

you can use like this

root@OpenWrt:/# ./test.sh lan
  1. Inquire the first IPv4 subnet of logical interface: network_get_subnet

. /lib/functions/network.sh

if [ "$#" -ne 1 ];then
    echo "Syntax:$0 interface"
    exit 1

network_get_subnet subnet $1
echo $subnet

you can use like this

root@OpenWrt:/# ./test.sh lan
  1. Inquire IPv4 gateway of logical interface: network_get_gateway

. /lib/functions/network.sh

if [ "$#" -ne 1 ];then
    echo "Syntax:$0 interface"
    exit 1

network_get_gateway gateway $1
echo $gateway

you can use like this

root@OpenWrt:/# ./test.sh lan
  1. Inquire DNS server of logical interface: network_get_dnsserver

. /lib/functions/network.sh

if [ "$#" -ne 1 ];then
    echo "Syntax:$0 interface"
    exit 1

network_get_dnsserver dnsserver $1
echo $dnsserver

you can use like this

root@OpenWrt:/# ./test.sh lan
  1. Inquire protocol of logical interface: network_get_protocol

. /lib/functions/network.sh

if [ "$#" -ne 1 ];then
    echo "Syntax:$0 interface"
    exit 1

network_get_protocol proto $1
echo $proto

you can use like this

root@OpenWrt:/# ./test.sh lan
  1. Inquire current state of logical interface: network_is_up

. /lib/functions/network.sh

if [ "$#" -ne 1 ];then
    echo "Syntax:$0 interface"
    exit 1

network_get_protocol $1

if [ $? = 0 ];then
    echo "up"
    echo "down"

you can use like this

root@OpenWrt:/# ./test.sh lan
root@OpenWrt:/# ifconfig eth0 down
root@OpenWrt:/# ./test.sh lan

enjoy network.sh. 🙂


Posted in LEDE, OpenWRT | 2 Comments

Build LoRaWAN Gateway with Ci40 and iC880a

In this post I will show you how to setup an OpenWRT based LoRaWAN gateway with Ci40 and iC880a. It has a user-friedly interface to config parameters.


  1. IMST iC880a SPI concentrator board
  2. Pigtail for antenna
  3. Ci40
  4. Power Supply 2A with micro USB
  5. MicroSD card
  6. RPi to iC8880a interface

Ci40 has a 40-pin header which is though not 100% compatible with Raspberry Pi. The header make it possible to connect lots of Raspberry Pi HATs such as this backplane from Tindie.


iC880a Description RPi pin Ci40 pin
21 Supply 5V 2 5v to Raspberry Pi board
22 GND 6 GND
13 Reset 22 MFIO_21
17 SPI Nss 24 SPI_M0_CS2 (MFIO_28)

Setting up the software

OpenWrt Preparation

At first, please following the instruction to prepare the OpenWrt on SD card. I prefer the SD card boot not normal because I want to save lifecycles of NAND FLASH on my board.

you don’t need to compile your own OpenWrt with lora-feed. I have prepared compiled ipk packages for this tutorial. Downloading these packages and copy to the SD card.

Install LoRa packages

From computer log in your Ci40 from serial or ssh.

$ opkg install libc_1.1.15-1_pistachio.ipk
$ opkg install libloragw_5.0.1-1_pistachio.ipk
$ opkg install lora-gateway-tests_5.0.1-1_pistachio.ipk
$ opkg install lora-gateway-utils_5.0.1-1_pistachio.ipk
$ opkg install packet-forwarder-utils_4.0.1-1_pistachio.ipk
$ opkg packet-forwarder_4.0.1-1_pistachio.ipk
$ opkg luci-app-pkt-fwd_1.0-1_all.ipk

You have all the necessary programs to start your LoRa gateway.
In my configuration, I use global_conf.json only and it will be automatically generated by Lua script. So please do not edit this file. The default configuration is for basic EU686 without GPS and beacon supports. You can change the configuration from LuCI interface as you wish.

Start LoRa gateway

Run the packet-forwarder by

$ /etc/init.d/lora_pkg_fwd start

If you want to automatically start after boot, you can do it by

$ /etc/init.d/lora_pkg_fwd enable

Posted in Ci40, LEDE, LoRa, OpenWRT | Leave a comment

Meet /etc/preinit again

*/etc/preinit is the init program after Linux kernel booted. It is briefly introduced in OpenWRT/LEDE: System Boot Sequence. This time I will meet it again and dive into it to search some internals.

As a reference, the code of preinit is shown below. And it is assumed that $PREINIT is already initialized.

# Copyright (C) 2006-2016 OpenWrt.org
# Copyright (C) 2010 Vertical Communications

[ -z "$PREINIT" ] && exec /sbin/init

export PATH="%PATH%"





. /lib/functions.sh
. /lib/functions/preinit.sh
. /lib/functions/system.sh

boot_hook_init preinit_essential
boot_hook_init preinit_main
boot_hook_init failsafe
boot_hook_init initramfs
boot_hook_init preinit_mount_root

for pi_source_file in /lib/preinit/*; do
    . $pi_source_file

boot_run_hook preinit_essential


boot_run_hook preinit_main

The first part includes three group of parameters. They are initilized for the functions which are located in hook list.

Then we come to five hook lists which are initilized by boot_hook_init which is located in /lib/function/boot.sh. The code of boot_hook_init is show below.

boot_hook_init() {          
    local hook="${1}_hook" # add suffix _hook to every hook lister name
    export -n "PI_STACK_LIST=${PI_STACK_LIST:+$PI_STACK_LIST }$hook"
    export -n "$hook="

The point of this function is the command export -n. The option -n means remove the export property from each NAME. It marks each NAME not export to the environment and child-env, but other functions in this shell can still use this variable.

for pi_source_file in /lib/preinit/*; do
    . $pi_source_file

preinit is then looking for and excute every files located /lib/preinit/. The name of such file is starting with a number and then the name of function. Each file has similar structure as

function_name1() {
function_name2() {
boot_hook_add hook_name function_name1
boot_hook_add hook_name function_name2

There can be multiple functions and later using boot_hook_add to add into a certain hook linker. So what happens in boot_hook_add is shown below

boot_hook_add() {
    local hook="${1}_hook${PI_HOOK_SPLICE:+_splice}"
    local func="${2}"

    [ -n "$func" ] && {
        local v; eval "v=\$$hook"
        export -n "$hook=${v:+$v }$func" # add function to responding hook list

After adding functions, preinit excutes the functions located in preinit_essential by

boot_run_hook preinit_essential

here the definition of boot_run_hook is shown below

boot_run_hook() {
    local hook="$1"
    local func
    while boot_hook_shift "$hook" func; do
        local ran; eval "ran=\$PI_RAN_$func"
        [ -n "$ran" ] || {
            export -n "PI_RAN_$func=1"
            $func "$1" "$2"  # excute the function

Here boot_hook_shift loops every functions in “$hook” until the last one. It returns 0 as true when there is still functions in “$hook” and returns 1 as false when reaching the end. The code of boot_hook_shift is shown below:

boot_hook_shift() {
    local hook="${1}_hook"
    local rvar="${2}"

    local v; eval "v=\$$hook" # $$hook includes all the registered functions
    [ -n "$v" ] && {
        local first="${v%% *}"  # take the first function every time

        [ "$v" != "${v#* }" ] && \
            export -n "$hook=${v#* }" || \
            export -n "$hook="

        export -n "$rvar=$first" # export the first function for other ones
        return 0

    return 1
Posted in Ci40, LEDE, OpenWRT | Leave a comment

iC880A LoRaWAN Gateway with Ci40

2017-06-27 15.13.19

with my lora-feed https://github.com/xueliu/lora-feed.

I am working on LuCi web interface to config the gateway. I will show it later.

Posted in Ci40, LEDE, LoRa, OpenWRT, 未分类 | Leave a comment