###### tags: `Construction`
# OpenWRT with LinkIt 7688
#### Basic requirement
| OS/Kernel | Version |
|:-------------------------- |:----------------------------------------|
| Host operating system | Linux Ubuntu 18.04 or 20.04 or 22.04 |
| Kernel | 4.15.0.142.lowlatency |
## OpenWRT Introduction

OpenWrt Project is a Linux operating system targeting embedded devices. Instead of trying to create a single, static firmware, OpenWrt provides a fully writable filesystem with package management. This frees you from the application selection and configuration provided by the vendor and allows you to customize the device through the use of packages to suit any application. For developers, OpenWrt is the framework to build an application without having to build a complete firmware around it; for users this means the ability for full customization, to use the device in ways never envisioned.
## OpenWRT Installation
#### Check files
```shell=
(LinkIt 7688) $ MTK LinkIt 7688 following MVC
(LinkIt 7688) $ /usr/lib/lua/luci/controller/*
(LinkIt 7688) $ /usr/lib/lua/luci/view/*
(LinkIt 7688) $ /usr/lib/lua/luci/model/cbi/*
```
#### Remote settings

#### Install requestments
```shell=
(LinkIt 7688) $ opkg update
(LinkIt 7688) $ opkg install luci
(LinkIt 7688) $ /etc/init.d/uhttpd restart
```
#### Background knowledge
* Lua: An lightweight, high-level, interpretive scripting language commonly used for embedded systems and as a configuration or extension script in various software products.
* Uci (Unified Configuration Interface): A consistent interface in OpenWrt designed for managing all system configurations. This standardization makes system administration more streamlined.
* Luci (Lua Configuration Interface): A web-based user interface for OpenWrt configuration. It is implemented using Lua, enabling web-based control and visualization of OpenWrt functionalities.
* MVC Framework (Model-View-Controller): A software architectural pattern primarily used for developing web applications. It divides the application into three interconnected components: Model (data), View (UI), and Controller (logic and server code). When creating a new feature or page, developers leverage the MVC structure, and in the context of OpenWrt with Lua, the system automatically handles many aspects once the Lua scripts are in place.
* CBI (Configuration Binding Interface): In the context of OpenWrt and Luci, CBI is a mechanism for binding configuration values to user interface elements. The mentioned "lua/luci/model/cbi" indicates the file path where CBI models might be located in the system.
#### MVC(Model、View、Controller) path

#### Create myapp
```shell=
(LinkIt 7688) $ cd /usr/lib/lua/luci/view/myapp-mymodule
(LinkIt 7688) $ vim helloworld.htm
<%+header%>
<h1><%: HelloWorld %></h1>
<%+footer%>
(LinkIt 7688) $ cd /usr/lib/lua/luci/controller
(LinkIt 7688) $ mkdir myapp
(LinkIt 7688) $ cd /usr/lib/lua/luci/controller/myapp
(LinkIt 7688) $ touch eric.lua
```
#### eric.lua
```shell=
(LinkIt 7688) $ vim eric.lua
module("luci.controller.myapp.eric", package.seeall)
function index()
--luci.template.render("path_to_your_template")
entry({"admin", "new_tab", "HelloWorld"}, template("myapp-mymodule/helloworld"), _("Hello World"), 10)
end
(LinkIt 7688) $ rm -r /tmp/luci-*
```


#### cbi file settings
```shell=
## vim cbi_file
(LinkIt 7688) $ cd /etc/config
config gateway_sn1 'SSID'
option SSID 'mwnl_mesh'
config gateway_sn2 'PASSWORD'
option PASSWORD 'test'
config wifi_switch 'wifi_switch'
option enabled '0'
config wifi_mode 'wifi_mode'
option mode 'ap'
config encryption 'encryption'
option type 'none'
config wifi_channel 'wifi_channel'
option type 'channel 6'
config wifi_limit 'wifi_limit'
option type '6'
config wifi_max_clients 'wifi_max_clients'
option max_clients '50'
config wifi_tx_power 'wifi_tx_power'
option tx_power '20'
```
#### myapp-mymodule settings
```shell=
(LinkIt 7688) $ cd /usr/lib/lua/luci/model/cbi/myapp-mymodule
(LinkIt 7688) $ vim gateway_sn1.lua
m = Map("cbi_file", translate("MWNL WiFi Settings")) -- cbi_file is the config file in /etc/config
-- SSID
d = m:section(TypedSection, "gateway_sn1") -- info is the section called info in cbi_file
a = d:option(Value, "SSID", translate("SSID"));
-- Password
d = m:section(TypedSection, "gateway_sn2") -- info is the section called info in cbi_file
a = d:option(Value, "PASSWORD", translate("PASSWORD"));
a.optional=false;
a.rmempty = false; -- name is the option in the cbi_file
-- Enable/Disable WiFi
d = m:section(TypedSection, "wifi_switch")
a = d:option(Flag, "enabled", translate("Enable WiFi"))
a.rmempty = false
-- WiFi Mode
d = m:section(TypedSection, "wifi_mode")
a = d:option(ListValue, "mode", translate("WiFi Mode"))
a:value("ap", translate("Access Point"))
a:value("client", translate("Client Mode"))
a:value("repeater", translate("Repeater"))
a.rmempty = false
-- Encryption Type
d = m:section(TypedSection, "encryption")
a = d:option(ListValue, "type", translate("Encryption Type"))
a:value("none", translate("None"))
a:value("wpa2", translate("WPA2"))
a:value("wpa3", translate("WPA3"))
-- WiFi Channel
d = m:section(TypedSection, "wifi_channel")
a = d:option(ListValue, "channel", translate("WiFi Channel"))
for i = 1, 11 do -- 2.4GHz channels
a:value(i, tostring(i))
end
--Max connection
d = m:section(TypedSection, "wifi_max_clients")
a = d:option(Value, "max_clients", translate("Max Connected Clients"))
a.datatype = "uinteger"
a.rmempty = false
--transmission power
d = m:section(TypedSection, "wifi_tx_power")
a = d:option(Value, "tx_power", translate("Transmission Power (mW)"))
a.datatype = "uinteger"
a.rmempty = false
return m
```
Web UI:http://10.33.7.76/cgi-bin/luci/admin/new_tab/sn1

## Use OpenWRT source code
```shell=
need to check your firmware, switch the correct branch
$ git clone https://github.com/openwrt/openwrt.git
OpenWrt v21.02.7: revert to branch defaults
```
## Development
To build your own firmware you need a GNU/Linux, BSD or MacOSX system (case sensitive filesystem required). Cygwin is unsupported because of the lack of a case sensitive file system.
## Requirements
You need the following tools to compile OpenWrt, the package names vary between distributions. A complete list with distribution specific packages is found in the Build System Setup documentation.
```shell=
gcc binutils bzip2 flex python3 perl make find grep diff unzip gawk getopt
subversion libz-dev libc-dev rsync which
```
## Quickstart
```shell=
$ ./scripts/feeds update -a
to obtain all the latest package definitions defined in feeds.conf / feeds.conf.default
$ ./scripts/feeds install -a
to install symlinks for all obtained packages into package/feeds/
$ make menuconfig
to select your preferred configuration for the toolchain, target system & firmware packages.
$ make
to build your firmware. This will download all sources, build the cross-compile toolchain and then cross-compile the GNU/Linux kernel & all chosen applications for your target system.
```
## Related Repositories
The main repository uses multiple sub-repositories to manage packages of different categories. All packages are installed via the OpenWrt package manager called opkg. If you're looking to develop the web interface or port packages to OpenWrt, please find the fitting repository below.
https://github.com/openwrt/luci
LuCI Web Interface: Modern and modular interface to control the device via a web browser.
https://github.com/openwrt/packages
OpenWrt Packages: Community repository of ported packages.
https://github.com/openwrt/routing.git
OpenWrt Routing: Packages specifically focused on (mesh) routing.
## Linkit-smart-feed
This feeds holds the SDK wifi driver and the config/meta package for the LinkIt Smart 7688 (Duo)
Note : LinkIt Smart 7688 uses the MediaTek proprietary Wi-Fi driver. While OpenWrt Chaos Calmer is evolving, only selected Linux kernel versions of it are supported by the Wi-Fi driver (3.18.21 ~ 3.18.44). If you are looking for a non-proprietary Wi-Fi driver, the mt76 project would be a reference of the choice.
## Build the firmware from sources

```shell=
## Install packages
$ sudo apt-get install git g++ make libncurses5-dev subversion libssl-dev gawk libxml-parser-perl unzip wget python xz-utils
## Prepare the default configuration file for feeds:
$ cd openwrt
$ cp feeds.conf.default feeds.conf
## Add the LinkIt Smart 7688 feed:
$ echo src-git linkit https://github.com/MediaTek-Labs/linkit-smart-7688-feed.git >> feeds.conf
Update the feed information of all available packages for building the firmware:
$ ./scripts/feeds update
$ ./scripts/feeds install -a
## Prepare the kernel configuration to inform OpenWrt that we want to build an firmware for LinkIt Smart 7688:
$ make menuconfig
Select the options as below:
Target System: MediaTek Ralink MIPS
Subtarget: MT76x8 based boards
Target Profile: MediaTek LinkIt Smart 7688
Save and exit ( use the deafult config file name without changing it )
```

```shell=
## Start the compilation process:
$ make
## if you need verbose information, use the V flag
$ make V=99
## After the build process completes, the resulted firmware file will be under bin/ramips/openwrt-ramips-mt7688-LinkIt7688-squashfs-sysupgrade.bin. Depending on the H/W resources of the host environment, the build process may take more than 30 minutes.
You can use this file to do the firmware upgrade through the Web UI. Or rename it to lks7688.imgfor upgrading through a USB drive.
$ cd $HOME/openwrt/bin/targets/ramips/mt76x8
```

# UCI API
```shell=
## Install the libuci library and the uci
$ opkg install libuci uci
```
## Libubox librabry install
```shell=
$ sudo apt-get install cmake
$ cd openwrt/dl
$ git clone https://github.com/yubo/libubox.git
$ tar xvf libubox-2021-05-16-b14c4688.tar
$ cd libubox-2021-05-16-b14c4688
$ cmake -D BUILD_LUA:BOOL=OFF -D BUILD_EXAMPLES:BOLL=OFF .
$ make
$ sudo make install
```
## UCI librabry install
```shell=
$ cd openwrt/dl
$ git clone https://github.com/jkjuopperi/uci.git
$ tar Jxvf uci-2021-04-14-4b3db117.tar.xz
$ cd uci-2021-04-14-4b3db117
$ cmake -D BUILD_LUA:BOOL=OFF .
$ make
$ sudo make install
$ sudo ldconfig
```
## LinkIt 7688 UCI config syntax
```shell=
## UCI config path => /etc/config
config 'section_type' 'section'
option 'key' 'value'
list 'list_key' 'list_value'
## UCI command
(LinkIt 7688) $ uci get cbi_file.SSID
gateway_sn1
(LinkIt 7688) $ uci show cbi_file.SSID
cbi_file.SSID=gateway_sn1
cbi_file.SSID.SSID='mwnl_mesh'
(LinkIt 7688) $ uci set cbi_file.SSID.SSID=mwnlmwnl
(LinkIt 7688) $ uci show cbi_file.SSID
cbi_file.SSID=gateway_sn1
cbi_file.SSID.SSID='mwnlmwnl'
(LinkIt 7688) $ uci commit cbi_file
```

## Golang works with shared object through cgo
```shell=
$ sudo apt-get install golang-go
```
```shell=
1. The `.so` file built from gcc should has the `lib` prefix
example: `libsum.so`, `libcalc.so`
2. The value after `LDFLAGS` should goes with name without `lib`
example:
a) `libsum.so` -> LDFLAGS=sum
a) `libcalc.so` -> LDFLAGS=calc
ChatGPT shows me a sum.c & main.go
// sum.c
#include "sum.h"
int sum(int a, int b) {
return a + b;
}
package main
/*
#cgo LDFLAGS: -L. -lsum
#include "sum.h"
*/
import "C"
import "fmt"
func main() {
// Call the sum function from the shared library
result := C.sum(5, 7)
// Print the result
fmt.Printf("Sum: %d\n", result)
}
I had put the files into following struct:
$ tree <project_folder>
.
├── lib
│ ├── sum.c
│ └── sum.h
└── main.go
With the build script:
$ cd <project_folder>/lib
$ gcc -shared -o libsum.so sum.c
$ cd <project_folder>
$ go build -o go_sum main.go
And here comes the first error:
$ go build -o go_sum main.go
# command-line-arguments
./main.go:5:10: fatal error: sum.h: No such file or directory
5 | #include "sum.h"
| ^~~~~~~
compilation terminated.
It’s not a big deal to us to create a sum.h header file.
// sum.h
#include <stdio.h>
int sum(int a, int b);
There should also put another compile flag: CFLAGS for cgo in main.go , then rebuild the Golang executable file
package main
/*
#cgo CFLAGS: -Ilib
#cgo LDFLAGS: -Llib -lsum
#include "sum.h"
*/
import "C"
import "fmt"
...
Once build successfully, just run the executable file with name go_sum
Unfortunately, another error pops !
$ ./go_sum
./go_sum: error while loading shared libraries: libsum.so: cannot open shared object file: No such file or directory
By searching and try-error for hours, I had found the solution which I should make the .so file been found by linker.
Here is the command where we can track the .so file information linked to a executable file:
$ ldd <executable file>
## Results for go_sum
$ ldd go_sum
linux-vdso.so.1 (0x00007ffde1aab000)
libsum.so => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6a85b55000)
/lib64/ld-linux-x86-64.so.2 (0x00007f6a85d86000)
As the result, the libsum.so has not been recognized, here is nothing consider with the .so itself, but the linker.
Solution
Here is key point to add the LD_LIBRARY_PATH
$ export LD_LIBRARY_PATH=<project_folder>/lib/
After the line execute, rebuild the Golang executable file, then check again the lib has been recognized with ldd command.
#e.q. export LD_LIBRARY_PATH=/home/eric/test/openwrt/golang/lib/
$ go build -o go_sum main.go
$ ldd go_sum
linux-vdso.so.1 (0x00007ffde1aab000)
libsum.so => <project_folder>/lib/libsum.so (0x00007ff959dbb000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6a85b55000)
/lib64/ld-linux-x86-64.so.2 (0x00007f6a85d86000)
$ ./go_sum
Sum: 12
```

## Golang compile
```shell=
$ GOOS=linux GOARCH=mips go build -o test test.go
or
$ GOOS=linux GOARCH=mipsel go build -o test test.go
$ scp test root@10.33.7.76:/root
## Openwrt Error logs
(LinkIt 7688) $ ./test: line 1: syntax error: unexpected "("
$ GOOS=linux GOARCH=mipsle GOMIPS=softfloat CGO_ENABLED=0 go build -o test test.go
$ GOOS=linux GOARCH=mipsle CGO_ENABLED=0 go build -o test test.go
$ scp test root@10.33.7.76:/root
(LinkIt 7688) $ ./test
Hello, OpenWRT!
```

## Cgo compile
```shell=
$ mipsel-openwrt-linux-gcc -shared -fPIC -o libsum.so sum.c
$ mipsel-openwrt-linux-gcc: command not found
$ find ~/research/openwrt -name mipsel-openwrt-linux-gcc
/home/eric/research/openwrt/openwrt-sdk-21.02.2-ramips-mt76x8_gcc-8.4.0_musl.Linux-x86_64/staging_dir/toolchain-mipsel_24kc_gcc-8.4.0_musl/bin/mipsel-openwrt-linux-gcc
/home/eric/research/openwrt/staging_dir/toolchain-mipsel_24kc_gcc-8.4.0_musl/bin/mipsel-openwrt-linux-gcc
$ export STAGING_DIR=/home/eric/research/openwrt/staging_dir
$ export PATH=$PATH:/home/eric/research/openwrt/openwrt-sdk-21.02.2-ramips-mt76x8_gcc-8.4.0_musl.Linux-x86_64/staging_dir/toolchain-mipsel_24kc_gcc-8.4.0_musl/bin
$ mipsel-openwrt-linux-gcc -shared -fPIC -o libsum.so sum.c
$ ls
go_sum libsum.so main.go sum.c sum.h
$ file libsum.so
libsum.so: ELF 32-bit LSB shared object, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, with debug_info, not stripped
$ GOOS=linux GOMIPS=softfloat GOARCH=mipsle CGO_ENABLED=1 CC=mipsel-openwrt-linux-gcc go build -o go_sum main.go
$ ./go_sum
-bash: ./go_sum: cannot execute binary file: Exec format error
$ scp go_sum root@10.33.7.76:/root
$ scp libsum.so root@10.33.7.76:/lib
```


## [Golang] environment variables
```shell=
$ go env # print all of environment variables
# -w sets environment variables
# -u removes environment variables
$ go env -w GOBIN=/somewhere/else/bin
$ go env -u GOBIN
$ go help env
```
# Cross Compiler about C programming
```shell=
$ sudo apt-get install build-essential subversion git-core libncurses5-dev zlib1g-dev gawk flex quilt libssl-dev xsltproc libxml-parser-perl mercurial bzr ecj cvs unzip
$ git clone https://github.com/openwrt/openwrt.git
$ cd openwrt
$ git checkout v21.02.1
$ ./scripts/feeds update -a
$ ./scripts/feeds install -a
$ make menuconfig
$ make
$ export PATH=$PATH:openwrt/staging_dir/toolchain-mipsel_24kc_gcc-8.4.0_musl/bin
$ vim helloworld.c
#include <stdio.h>
int main()
{
printf("This is my hello word!\n");
return 0;
}
$ mipsel-linux-gnu-gcc -o helloworld helloworld.c
$ scp helloworld root@10.33.7.76:/root/
```
# OpenWRT SDK
```shell=
## Local to remote server
$ scp -r Downloads/openwrt-sdk-21.02.2-ramips-mt76x8_gcc-8.4.0_musl.Linux-x86_64.tar.xz eric@10.33.7.32:/home/eric/test/openwrt/
## remote server
$ cd openwrt
$ tar -xf openwrt-sdk-21.02.2-ramips-mt76x8_gcc-8.4.0_musl.Linux-x86_64.tar.xz
$ cd openwrt-sdk-21.02.2-ramips-mt76x8_gcc-8.4.0_musl.Linux-x86_64
$ export PATH=$PATH:/home/eric/test/openwrt/openwrt-sdk-21.02.2-ramips-mt76x8_gcc-8.4.0_musl.Linux-x86_64/staging_dir/toolchain-mipsel_24kc_gcc-8.4.0_musl/bin/
$ export STAGING_DIR=/home/eric/test/openwrt/openwrt-sdk-21.02.2-ramips-mt76x8_gcc-8.4.0_musl.Linux-x86_64/staging_dir
## Check mipsel-openwrt-linux-gcc version
$ mipsel-openwrt-linux-gcc --version
## vim helloworld.c
#include <stdio.h>
int main(){
printf("hello world!\n");
return 0;
}
$ mipsel-openwrt-linux-gcc -o helloworld helloworld.c
$ ./helloworld
bash: ./helloworld: cannot execute binary file: Exec format erro
$ scp helloworld root@10.33.7.76:/root
## root@10.33.7.76
(LinkIt 7688) $ ./helloworld
hello world!
```

## Linkit 7688 version
```shell=
(LinkIt 7688) $ cat /etc/openwrt_release
(LinkIt 7688) $ chmod +x ./helloworld
(LinkIt 7688) $ ./helloworld
```

## Compile environment (SDK for .ipk)
A cross-compiler has been set up, which can compile native C code into executable files and run them on OpenWRT. However, such an environment is ultimately not a standard development environment and cannot produce .ipk packages manageable via OPKG. Next, we will set up an SDK environment and produce .ipk installation packages.
```shell=
$ cd /research/openwrt/openwrt-sdk-21.02.2-ramips-mt76x8_gcc-8.4.0_musl.Linux-x86_64/package/hello/src
$ vim helloworld.c
#include <stdio.h>
int main()
{
printf("This is my hello word!\n");
return 0;
}
$ vim Makefile
helloworld : helloworld.o
$(CC) $(LDFLAGS) helloworld.o -o helloworld
helloworld.o : helloworld.c
$(CC) $(CFLAGS) -c helloworld.c
clean :
rm *.o helloworld
$ make
cc -c helloworld.c
cc helloworld.o -o helloworld
$ ./helloworld
This is my hello word!
## Data Structure:
package
|-- hello
| |-- Makefile (正在編輯的檔案, 用以 make .ipk 檔案)
| `-- src
| |-- helloworld.c
| `-- Makefile (用以單機測試的檔案)
`-- Makefile (OpenWRT SDK )
```
## Makefile
```shell=
include $(TOPDIR)/rules.mk
# Name, version and release number
# The name and version of your package are used to define the variable to point to the build directory of your package: $(PKG_BUILD_DIR)
PKG_NAME:=helloworld
PKG_VERSION:=1.0
PKG_RELEASE:=1
# Source settings (i.e. where to find the source codes)
# This is a custom variable, used below
################
SOURCE_DIR:=$HOME/openwrt/openwrt-sdk-21.02.2-ramips-mt76x8_gcc-8.4.0_musl.Linux-x86_64/package/hello/src
###############
# Write to helloworld.c folder
include $(INCLUDE_DIR)/package.mk
# Package definition; instructs on how and where our package will appear in the overall configuration menu ('make menuconfig')
define Package/helloworld
SECTION:=examples
CATEGORY:=Examples
TITLE:=Hello, World!
endef
# Package description; a more verbose description on what our package does
define Package/helloworld/description
A simple "Hello, world!" -application.
endef
# Package preparation instructions; create the build directory and copy the source code.
# The last command is necessary to ensure our preparation instructions remain compatible with the patching system.
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
cp $(SOURCE_DIR)/* $(PKG_BUILD_DIR)
$(Build/Patch)
endef
# Package build instructions; invoke the target-specific compiler to first compile the source file, and then to link the file into the final executable
define Build/Compile
$(TARGET_CC) $(TARGET_CFLAGS) -o $(PKG_BUILD_DIR)/helloworld.o -c $(PKG_BUILD_DIR)/helloworld.c
$(TARGET_CC) $(TARGET_LDFLAGS) -o $(PKG_BUILD_DIR)/$1 $(PKG_BUILD_DIR)/helloworld.o
endef
# Package install instructions; create a directory inside the package to hold our executable, and then copy the executable we built previously into the folder
define Package/helloworld/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/helloworld $(1)/usr/bin
endef
# This command is always the last, it uses the definitions and variables we give above in order to get the job done
$(eval $(call BuildPackage,helloworld))
```
Use make menuconfig to select the target to compile:


```shell=
$ cd home/eric/research/openwrt
$ make package/hello/compile V=99
$ cd openwrt-sdk-21.02.2-ramips-mt76x8_gcc-8.4.0_musl.Linux-x86_64/bin/packages/mipsel_24kc/base
$ ls
helloworld_1.0-1_mipsel_24kc.ipk
$ scp helloworld_1.0-1_mipsel_24kc.ipk root@10.33.7.76:/root
```
```shell=
(LinkIt 7688) $ ls
helloworld_1.0-1_mipsel_24kc.ipk
(LinkIt 7688) $ helloworld
This is my hello word!
```

# MQTT Introduction
MQTT (Message Queuing Telemetry Transport) is a communication architecture developed by IBM specifically for the Internet of Things (IoT). This architecture is built on top of TCP/IP and is specially designed for the unique characteristics of IoT, providing a lightweight communication structure optimized for unstable networks. MQTT operates based on a pub/sub (publish/subscribe) model. Within its network, there's a broker that acts as an intermediary for information. Devices can either "publish" a message to a specific "topic" and send it to the broker, or "subscribe" to a topic to retrieve information from the broker, as illustrated in the diagram below:

Considering the application scenarios of the Internet of Things (IoT), MQTT has a unique QoS (Quality of Service) design, tailored for different data levels. Three QoS levels ranging from 0-2 are designed as follows:
QoS 0: At most once (Message is delivered at most once)
QoS 1: At least once (Message is delivered at least once, ensuring delivery)
QoS 2: Exactly once (Message is delivered exactly one time, ensuring no duplicates)
Different QoS levels correspond to various communication needs and the respective number of control packets. In the definition of QoS, all transmission behavior refers to "publish". As illustrated in the subsequent diagram, we can observe that QoS 0 is analogous to the "best effort" transmission mechanism. QoS 1 includes an acknowledgment (ACK) from the broker upon receipt, while QoS 2 employs a two-way ACK mechanism.

In this diagram, we can also see the difference between MQTT and a regular Message Queue. The MQTT broker doesn't cache the information it receives. Once an ACK is received and the message is deleted, it won't continue to be retained in the system, and thus, won't be received by subscribing users.
# MQTT testing on OpenWRT
On OpenWRT, there are already standard MQTT implementations (mosquitto-ssl, mosquitto-nossl), which are based on the MQTT 3.1 standard (i.e., the first standard proposed by IBM). For more detailed information, refer to:
https://openwrt.org/packages/pkgdata_lede17_1/mosquitto-nossl
https://mosquitto.org/blog/2011/08/mosquitto-on-openwrt/
Run in the root directory of OpenWRT SDK:
```shell=
$ ./scripts/feeds update -a
$ ./scripts/feeds install mosquitto
$ cd openwrt-sdk-21.02.2-ramips-mt76x8_gcc-8.4.0_musl.Linux-x86_64/bin/packages/mipsel_24kc/packages
$ ls
cJSON_1.7.14-3_mipsel_24kc.ipk libmosquittopp_2.0.13-1_mipsel_24kc.ipk libwebsockets-openssl_3.1.0-2_mipsel_24kc.ipk Packages
libcap_2.43-1_mipsel_24kc.ipk libmosquitto-ssl_2.0.13-1_mipsel_24kc.ipk mosquitto-client-nossl_2.0.13-1_mipsel_24kc.ipk Packages.gz
libcap-bin_2.43-1_mipsel_24kc.ipk libuv1_1.40.0-3_mipsel_24kc.ipk mosquitto-client-ssl_2.0.13-1_mipsel_24kc.ipk Packages.manifest
libcares_1.17.2-1_mipsel_24kc.ipk libwebsockets-full_3.1.0-2_mipsel_24kc.ipk mosquitto-nossl_2.0.13-1_mipsel_24kc.ipk
libmosquitto-nossl_2.0.13-1_mipsel_24kc.ipk libwebsockets-mbedtls_3.1.0-2_mipsel_24kc.ipk mosquitto-ssl_2.0.13-1_mipsel_24kc.ipk
$ scp * root@10.33.7.76:/root
```
Install packages on OpenWRT:
```shell=
(LinkIt 7688) $ opkg update
(LinkIt 7688) $ opkg install cJSON_1.7.14-3_mipsel_24kc.ipk
(LinkIt 7688) $ opkg install libcap-bin_2.43-1_mipsel_24kc.ipk
(LinkIt 7688) $ opkg install libcap_2.43-1_mipsel_24kc.ipk
(LinkIt 7688) $ opkg install libcares_1.17.2-1_mipsel_24kc.ipk
(LinkIt 7688) $ opkg install libmosquitto-nossl_2.0.13-1_mipsel_24kc.ipk
(LinkIt 7688) $ opkg install libmosquitto-ssl_2.0.13-1_mipsel_24kc.ipk
(LinkIt 7688) $ opkg install libmosquittopp_2.0.13-1_mipsel_24kc.ipk
(LinkIt 7688) $ opkg install libuv1_1.40.0-3_mipsel_24kc.ipk
(LinkIt 7688) $ opkg install libwebsockets-full_3.1.0-2_mipsel_24kc.ipk
(LinkIt 7688) $ opkg install libwebsockets-mbedtls_3.1.0-2_mipsel_24kc.ipk
(LinkIt 7688) $ opkg install libwebsockets-openssl_3.1.0-2_mipsel_24kc.ipk
(LinkIt 7688) $ opkg install mosquitto-client-nossl_2.0.13-1_mipsel_24kc.ipk
(LinkIt 7688) $ opkg install mosquitto-client-ssl_2.0.13-1_mipsel_24kc.ipk
(LinkIt 7688) $ opkg install mosquitto-nossl_2.0.13-1_mipsel_24kc.ipk
(LinkIt 7688) $ opkg install mosquitto-ssl_2.0.13-1_mipsel_24kc.ipk
```
There are three packages in total, corresponding to the broker (mosquitto), client (mosquitto-client), and library (libmosquitto). In other words, this MQTT implementation of mosquitto supports the functionality of data publishing or subscribing on OpenWRT. Additionally, it can also serve as an MQTT broker, making the WiFi AP act as an IoT intermediary, gathering information from various nodes within the WiFi network.
Once installed, there are three packages:

Mosquitto plays the role of a broker and supports MQTT version 3.1. Through commands, the port used by MQTT can be set, and it can also run in the background on OpenWRT.

# MQTT development on OpenWRT
```shell=
## Server
$ sudo apt-get update
$ sudo apt-get install mosquitto mosquitto-clients
$ sudo apt-get install libmosquitto-dev
$ sudo ufw disable
## Publish messages from server
$ mosquitto_pub -h localhost -t "some/topic" -m "Hello, LinkIt!"
```
```shell=
## Openwrt
(LinkIt 7688) $ /etc/init.d/firewall stop
(LinkIt 7688) $ /etc/init.d/firewall disable
## /etc/init.d/firewall start
## pidof mosquitto
## LinkIt 7688 subscribe topic
(LinkIt 7688) $ mosquitto_sub -h YOUR_SERVER_IP -t "some/topic"
## LinkIt 7688's mosquitto_sub output can see "Hello, LinkIt!"
```

## MQTT C code
Before developing on OpenWRT, start by writing a simple program to test the functionality of MQTT. Considering the support for OpenWRT, the mosquitto API is used for development. The program mainly focuses on the "publish" function, directing the "subscribe" target to "info", and adding a new "publish" pointing to "report". Given that the original program structure would constantly wait for subscribed information in a loop, we first execute a "publish" before "subscribe". Here is the program code:
```shell=
vim mqtt.c
```
```shell=
#include <stdio.h>
#include <mosquitto.h>
void my_message_callback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message)
{
if(message->payloadlen){
printf("%s %s\n", message->topic, message->payload);
}else{
printf("%s (null)\n", message->topic);
}
fflush(stdout);
}
void my_connect_callback(struct mosquitto *mosq, void *userdata, int result)
{
if(!result){
/* Subscribe to the specified topic on successful connect. */
mosquitto_subscribe(mosq, NULL, "some/topic", 2); // Modified line
}else{
fprintf(stderr, "Connect failed\n");
}
}
void my_subscribe_callback(struct mosquitto *mosq, void *userdata, int mid, int qos_count, const int *granted_qos)
{
int i;
printf("Subscribed (mid: %d): %d", mid, granted_qos[0]);
for(i=1; i<qos_count; i++){
printf(", %d", granted_qos[i]);
}
printf("\n");
}
int main(int argc, char *argv[])
{
char *host = "10.33.7.32"; // Modified line
int port = 1883;
int keepalive = 60;
bool clean_session = true;
struct mosquitto *mosq = NULL;
mosquitto_lib_init();
mosq = mosquitto_new(NULL, clean_session, NULL);
if(!mosq){
fprintf(stderr, "Error: Out of memory.\n");
return 1;
}
mosquitto_connect_callback_set(mosq, my_connect_callback);
mosquitto_message_callback_set(mosq, my_message_callback);
mosquitto_subscribe_callback_set(mosq, my_subscribe_callback);
if(mosquitto_connect(mosq, host, port, keepalive)){
fprintf(stderr, "Unable to connect.\n");
return 1;
}
mosquitto_publish(mosq, NULL, "report", sizeof("hello"), "hello", 2, false);
mosquitto_loop_forever(mosq, -1, 1);
mosquitto_destroy(mosq);
mosquitto_lib_cleanup();
return 0;
}
```
## MQTT Publisher, Broker and Subscriber

```shell=
## Server
$ gcc mqtt.c -o mqtt -lmosquitto
$ ./mqtt
## Server open another terminal
$ mosquitto_pub -h 10.33.7.32 -t "some/topic" -m "NCU mwnl"
## Openwrt
(LinkIt 7688) $ mosquitto_sub -h 10.33.7.32 -t "some/topic" -d
```


## Reference
https://doc.embedfire.com/openwrt/user_manal/zh/latest/User_Manual/compile/make_menuconfig.html
https://openwrt-nctu.gitbook.io/project/openwrt-compile-env/openwrt-cross-compiler
https://blog.csdn.net/qq_28812525/article/details/103870169
https://blog.csdn.net/qq_28812525/article/details/103881723
https://blog.csdn.net/qq_28812525/article/details/103902872
https://archive.openwrt.org/releases/21.02.2/targets/ramips/mt76x8/
https://segmentfault.com/q/1010000022621510
https://serverfault.com/a/201711
https://zhuanlan.zhihu.com/p/57163950