【openwrt應(yīng)用開發(fā)】openwrt交叉編譯自己的應(yīng)用程序入門
類似minicom串口終端at應(yīng)用程序開發(fā)
準(zhǔn)備
開發(fā)板: SUN7628 (MT7628 ROM:32MB RAM:128MB)
openwrt源碼:?OpenWrt Chaos Calmer(CC) 15.05.1 r49396
前提:編譯Openwrt源碼包通過
OpenWrt應(yīng)用程序開發(fā)方式
OpenWrt上面應(yīng)用程序開發(fā)有兩種方式:
1、利用OpenWrt SDK,
2、利用OpenWrt源碼。
其實(shí)過程都差不是很多。源碼會直接生成可執(zhí)行程序的demo,SDK只生成ipk包,進(jìn)行opkg安裝。
在編譯根目錄下會有一個(gè)dl的目錄,這個(gè)目錄其實(shí)是“download”的簡寫,在編譯前期,需要從網(wǎng)絡(luò)下載的數(shù)據(jù)包都會放在這個(gè)目錄下,這些軟件包的一個(gè)特點(diǎn)就是,會自動安裝在所編譯的固件中,也就是我們make menuconfig的時(shí)候,為固件配置的一些軟件包。如果我們需要更改這些源碼包,只需要將更改好的源碼包打包成相同的名字放在這個(gè)目錄下,然后開始編譯即可。編譯時(shí),會將軟件包解壓到build_dir目錄下。
OpenWrt應(yīng)用程序開發(fā)
很多入門教程都寫hellowrold, 寫helloword沒什么實(shí)際用途,本次制作一個(gè)類似minicom串口終端, 我命名為at, minicom太大,我們自己寫的at非常小,使用簡單方便,相信大家用后會愛不釋手。
下面我們利用OpenWrt源碼開發(fā)at:
1、進(jìn)入package目錄,創(chuàng)建軟件目錄
#cd openwrt/package
#mkdir at
2、進(jìn)入test目錄,創(chuàng)建Makefile文件和代碼路徑
├── at
? ???├── Makefile
? ???└── src
? ?? ?? ? ├── at.c
? ?? ?? ? └── Makefile
該Makefile基本內(nèi)容格式都差不多,可參照以下進(jìn)行修改
#
# Copyright (C) 2009-2010 Jo-Philipp Wich
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
# 導(dǎo)入通用編譯規(guī)則
include $(TOPDIR)/rules.mk
# name和version用來定義編譯目錄名$(PKG_BUILD_DIR)]
PKG_NAME:=at
PKG_VERSION:=1.0
PKG_RELEASE:=1
#PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)??# 也可以直接定義編譯目錄名,代替默認(rèn)的目錄名
# 導(dǎo)入包定義
include $(INCLUDE_DIR)/package.mk
# 包定義:定義我們的包在menuconfig中的位置
# Makefile中的define語法可以理解為函數(shù),用于定義命令集合
define Package/at
??SECTION:=utils
??CATEGORY:=Base system
??TITLE:=at, uart at from example.
endef
# 包描述:關(guān)于我們包的更詳細(xì)的描述
define Package/at/description
??A simple at example for uart utils, my first openwrt package example.
endef
# 編譯準(zhǔn)備. 必須使用tab縮進(jìn),表示是可執(zhí)行的命令
define Build/Prepare
? ?? ???echo "Here is Build/Prepare at"
? ?? ???mkdir -p $(PKG_BUILD_DIR)
? ?? ???cp ./src/* $(PKG_BUILD_DIR)/
endef
# 安裝
define Package/at/install
? ?? ???$(INSTALL_DIR) $(1)/usr/bin
? ?? ???$(INSTALL_BIN) $(PKG_BUILD_DIR)/at $(1)/usr/bin
endef
# 這一行總是在最后
$(eval $(call BuildPackage,at))
復(fù)制代碼
注意以上凡是命令行,必須以tab開頭,否則會出現(xiàn)Makefile *** missing separator.??Stop.
#mkdir??src
3、進(jìn)入src目錄,創(chuàng)建相關(guān)源文件
#cd src
創(chuàng)建源文件at.c,如下
/*
* at
* Like minicom
* Usage: ./at /dev/ttyx
* lojam
* http://bbs.sunsili.com
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int ttyfd;
int stdout_changed = 0;
int tty_changed = 0;
struct termios stdout_tio;
struct termios tty_tio;
void restore_tio()
{
? ? if(stdout_changed)
? ? {
? ?? ???stdout_tio.c_lflag |= ECHO;
? ?? ???tcsetattr(STDIN_FILENO, TCSANOW, &stdout_tio);
? ? }
? ? if(tty_changed)
? ? {
? ?? ???tcsetattr(ttyfd, TCSANOW, &tty_tio);
? ? }
}
void int_handler(int signum)
{
? ? close(ttyfd);
? ? exit(EXIT_SUCCESS);
}
int main(int args, const char *argv[])
{
? ? char readBuf[256];
? ? const char *ttyPath = argv[1];
? ? const char *atCommand = argv[2];
? ? struct termios tio;
? ? int ret;
? ? if(args !=2 )
? ? {
? ?? ???fprintf(stderr, "Usage: ./at /dev/ttyx ");
? ?? ???exit(EXIT_FAILURE);
? ? }
? ? atexit(restore_tio);
? ? ttyfd = open(ttyPath, O_RDWR | O_NOCTTY | O_NDELAY);
? ? if(ttyfd < 0)
? ? {
? ?? ???perror("open");
? ?? ???exit(EXIT_FAILURE);
? ? }
? ? signal(SIGINT, int_handler);
? ? ret = tcgetattr(ttyfd, &tio);
? ? if (ret == -1)
? ?? ???{
? ?? ?? ?? ?? ? perror("tcgetattr");
? ?? ?? ?? ?? ? exit(EXIT_FAILURE);
? ?? ???}
? ?? ???memcpy(&tty_tio, &tio, sizeof(struct termios));
? ?? ???tio.c_iflag = 0;
? ?? ???tio.c_oflag = 0;
? ?? ???tio.c_cflag = CS8 | CREAD | CLOCAL;
? ?? ???tio.c_cflag &= (~CRTSCTS);
? ?? ???tio.c_lflag = 0;
? ?? ???tio.c_cc[VMIN] = 1;
? ?? ???tio.c_cc[VTIME] = 0;
? ?? ???if (cfsetospeed(&tio, B115200) < 0 || cfsetispeed(&tio, B115200) < 0)
? ?? ???{
? ?? ?? ?? ?? ? perror("cfseti/ospeed");
? ?? ?? ?? ?? ? exit(EXIT_FAILURE);
? ?? ???}
? ?? ???ret = tcsetattr(ttyfd, TCSANOW, &tio);
? ?? ???if (ret == -1)
? ?? ???{
? ?? ?? ?? ?? ? perror("tcsetattr");
? ?? ?? ?? ?? ? exit(EXIT_FAILURE);
? ?? ???}
? ?? ???tty_changed = 1;
? ?? ???struct termios outio;
? ?? ???ret = tcgetattr(STDIN_FILENO, &outio);
? ?? ???if (ret == -1)
? ?? ???{
? ?? ?? ?? ?? ? perror("tcgetattr");
? ?? ?? ?? ?? ? exit(EXIT_FAILURE);
? ?? ???}
? ?? ???memcpy(&stdout_tio, &outio, sizeof(struct termios));
? ?? ???stdout_changed = 1;
? ?? ???outio.c_lflag &= ~ECHO;
? ?? ???ret = tcsetattr(STDIN_FILENO, TCSANOW, &outio);
? ?? ???int flags = fcntl(STDIN_FILENO, F_GETFL, 0);
? ?? ???fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
? ?? ???struct pollfd fds[] = {
? ?? ?? ?? ?? ? {STDIN_FILENO, POLLIN, 0},
? ?? ?? ?? ?? ? {ttyfd, POLLIN, 0}
? ?? ???};
? ?? ???while (1)
? ?? ???{
? ?? ?? ?? ?? ? ret = poll(fds, sizeof(fds)/sizeof(struct pollfd), 0);
? ?? ?? ?? ?? ? if (ret == -1)
? ?? ?? ?? ?? ? {
? ?? ?? ?? ?? ?? ?? ?? ?perror("poll");
? ?? ?? ?? ?? ?? ?? ?? ?exit(EXIT_FAILURE);
? ?? ?? ?? ?? ? }
? ?? ?? ?? ?? ? if (fds[0].revents & POLLIN)
? ?? ?? ?? ?? ? {
? ?? ?? ?? ?? ?? ?? ?? ?memset(readBuf, 0, sizeof(readBuf));
? ?? ?? ?? ?? ?? ?? ?? ?ret = read(fds[0].fd, readBuf, sizeof(readBuf));
? ?? ?? ?? ?? ?? ?? ?? ?if (ret < 0 && errno != EAGAIN)
? ?? ?? ?? ?? ?? ?? ?? ?{
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???perror("read");
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???exit(EXIT_FAILURE);
? ?? ?? ?? ?? ?? ?? ?? ?}
? ?? ?? ?? ?? ?? ?? ?? ?if (ret > 0)
? ?? ?? ?? ?? ?? ?? ?? ?{
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???strcpy(readBuf+ret-1, " ");
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???// printf("%s", readBuf);
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???ret = write(ttyfd, readBuf, strlen(readBuf));
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???if (ret < 0)
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???{
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? perror("write");
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? exit(EXIT_FAILURE);
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???}
? ?? ?? ?? ?? ?? ?? ?? ?}
? ?? ?? ?? ?? ? }
? ?? ?? ?? ?? ? if (fds[1].revents & POLLIN)
? ?? ?? ?? ?? ? {
? ?? ?? ?? ?? ?? ?? ?? ?memset(readBuf, 0, sizeof(readBuf));
? ?? ?? ?? ?? ?? ?? ?? ?ret = read(fds[1].fd, readBuf, sizeof(readBuf));
? ?? ?? ?? ?? ?? ?? ?? ?if (ret == -1 && errno != EAGAIN)
? ?? ?? ?? ?? ?? ?? ?? ?{
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???perror("read");
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???exit(EXIT_FAILURE);
? ?? ?? ?? ?? ?? ?? ?? ?}
? ?? ?? ?? ?? ?? ?? ?? ?printf("%s", readBuf);
? ?? ?? ?? ?? ? }
? ?? ???}
? ?? ???int commandLen = strlen(atCommand);
? ?? ???char *buf = (char *)malloc(commandLen + 3);
? ?? ???sprintf(buf, "%s ", atCommand);
? ?? ???ret = write(ttyfd, buf, strlen(buf));
? ?? ???if (ret < 0)
? ?? ???{
? ?? ?? ?? ?? ? perror("write");
? ?? ?? ?? ?? ? exit(EXIT_FAILURE);
? ?? ???}
? ?? ???free(buf);
? ?? ???while (1)
? ?? ???{
? ?? ?? ?? ?? ? ret = read(ttyfd, readBuf, sizeof(readBuf));
? ?? ?? ?? ?? ? if (ret < 0 && errno != EAGAIN)
? ?? ?? ?? ?? ? {
? ?? ?? ?? ?? ?? ?? ?? ?perror("read");
? ?? ?? ?? ?? ?? ?? ?? ?exit(EXIT_FAILURE);
? ?? ?? ?? ?? ? }
? ?? ?? ?? ?? ? if (ret > 0)
? ?? ?? ?? ?? ?? ?? ?? ?write(1, readBuf, ret);
? ?? ???}
? ?? ???return 0;
}
復(fù)制代碼
創(chuàng)建源文件的Makefile
TARGET = at
OBJS = at.o
$(TARGET):$(OBJS)
? ?? ???$(CC) $(LDFLAGS) -o $@ $^
%.o: %.c
? ?? ???$(CC) $(CFLAGS) -c [? ?? ???DISCUZ_CODE_11? ?? ???]lt; -o $@
.PHONY: clean
clean:
? ?? ???rm -f $(TARGET) $(OBJS)
復(fù)制代碼
編譯
4、回到頂層目錄
make menuconfig
Base system —>
? ?? ?? ?? ? at
選中行按空格鍵我們剛剛創(chuàng)建的at。保存退出
單獨(dú)編譯at模塊
make package/at/compile V=s
make[1]: Entering directory '/home/fan/openwrt_CC_mt76xx_omj_source'
make[2]: Entering directory '/home/fan/openwrt_CC_mt76xx_omj_source/package/libs/toolchain'
if [ -f /home/fan/openwrt_CC_mt76xx_omj_source/staging_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/pkginfo/toolchain.default.install.clean ]; then rm -f /home/fan/openwrt_CC_mt76xx_omj_source/staging_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/pkginfo/toolchain.default.install /home/fan/openwrt_CC_mt76xx_omj_source/staging_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/pkginfo/toolchain.default.install.clean; fi; echo "libc" >> /home/fan/openwrt_CC_mt76xx_omj_source/staging_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/pkginfo/toolchain.default.install
.........
make[2]: Leaving directory '/home/fan/openwrt_CC_mt76xx_omj_source/package/at'
make[1]: Leaving directory '/home/fan/openwrt_CC_mt76xx_omj_source'
不出意外,就編譯好了
也可以編譯openwrt固件時(shí)編譯,編譯固件,參考:【openwrt】基于 WSL的openwrt開發(fā)環(huán)境(構(gòu)建系統(tǒng))配置-谷動谷力 (sunsili.com)
觀察編譯過程可以發(fā)現(xiàn)交叉編譯工具為CC="mips-openwrt-linux-uclibc-gcc"??位置大概是./staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/mips-openwrt-linux-uclibc/bin/
編譯成功后,
#ls build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/at-1.0/at??at.c??at.o??ipkg-ramips_24kec??Makefile
?
編譯openwrt打包進(jìn)固件
直接make (-j8??需要電腦支持)
編譯成功后
生成ipk安裝好
.......
Generating index for package ./at_1.0-1_ramips_24kec.ipk??
......
at應(yīng)用程序存放位置
ls staging_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/root-ramips/usr/bin/
可以找到 at
at_1.0-1_ramips_24kec.ipk ipk包存放位置
ls??bin/ramips/packages/base/
可以找到 at_1.0-1_ramips_24kec.ipk
測試
單獨(dú)編譯的at模塊
用scp拷貝at到開發(fā)板,執(zhí)行就ok了。
scp build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/at-1.0/at root@19
2.168.3.125:/root
root@192.168.3.125's password: #輸入openwrt開發(fā)板密碼
at? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?100%? ?12KB??12.2KB/s? ?00:00
等待傳輸完成
ssh登錄開發(fā)板(可以用可視化工具,如mobaxterm,點(diǎn)擊可以查看用法)
ssh?root@192.168.3.125
root@192.168.3.125's password:#輸入openwrt開發(fā)板密碼
BusyBox v1.23.2 (2023-07-31 0921 CST) built-in shell (ash)
??_______? ?? ?? ?? ?? ?? ?? ?________? ?? ???__
|? ?? ? |.-----.-----.-----.|??|??|??|.----.|??|_
|? ?-? ?||??_??|??-__|? ???||??|??|??||? ?_||? ?_|
|_______||? ?__|_____|__|__||________||__|??|____|
? ?? ?? ? |__| W I R E L E S S? ?F R E E D O M
-----------------------------------------------------
CHAOS CALMER (Chaos Calmer, r49396)
-----------------------------------------------------
??* 1 1/2 oz Gin? ?? ?? ?? ?Shake with a glassful
??* 1/4 oz Triple Sec? ?? ? of broken ice and pour
??* 3/4 oz Lime Juice? ?? ? unstrained into a goblet.
??* 1 1/2 oz Orange Juice
??* 1 tsp. Grenadine Syrup
-----------------------------------------------------
root@SUN:~# ls -la
.....
-rwxr-xr-x? ? 1 root? ???root? ?? ?? ?12487 Aug??1 14:06 at #綠色的, 可執(zhí)行的, root有執(zhí)行權(quán)限
....
在開發(fā)板運(yùn)行at測試一下, 我開發(fā)板開有一個(gè)Air724模塊,用ttyUSB0端
Usage: ./at??/dev/ttyUSB0
運(yùn)行加端口號即可
root@TJ:~# ./at /dev/ttyUSB0
ATI #發(fā)行AT指令
AirM2M_Air724UG_V401876_LTE_AT??#Air724模塊 返回Air724模塊軟硬件相關(guān)信息
OK
同時(shí)ctrl+c 可以退出 at 應(yīng)用
openwrt打包編譯
用scp拷貝at_1.0-1_ramips_24kec.ipk到開發(fā)板
scp ./bin/ramips/packages/base/at_1.0-1_ramips_24kec.ipk?root@192.168.3
.125:/tmp
root@192.168.3.125's password:
at_1.0-1_ramips_24kec.ipk? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? 100% 3108? ???3.0KB/s? ?00:00
等待傳輸完成
安裝at
在開發(fā)板上運(yùn)行
root@SUN:~# opkg install /tmp/at_1.0-1_ramips_24kec.ipk
Installing at (1.0-1) to root...
Configuring at.
運(yùn)行at (安裝后,無論在何目錄下,都不用加./ 加路徑,可以直接用at /dev/ttyx 運(yùn)行
root@SUN:~# at /dev/ttyUSB0
ATI
AirM2M_Air724UG_V401876_LTE_AT
OK
燒錄固件
用scp拷貝penwr升級固件k到開發(fā)板
scp bin/ramips/openwrt-ramips-mt7628-mt7628-squashfs-sysupgrade.bin?root@192.168.3.125:/tmp
root@192.168.3.125's password:
openwrt-ramips-mt7628-mt7628-squashfs-sysupgrade.bin? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? 100% 8704KB? ?1.1MB/s? ?00:08
開發(fā)板運(yùn)行:
sysupgrade -n -F /tmp/openwrt-ramips-mt7628-mt7628-squashfs-sysupgrade.bin
詳細(xì)說明openwrtl固件升級,請參考:openwrt怎么升級固件?使用命令sysupgrade實(shí)現(xiàn)openwrt升級固件-谷動谷力 (sunsili.com)
燒錄后,at會存放在開發(fā)析的 /usr/bin目錄下,不用安裝,無論在何目錄下,都不用加./ 加路徑,可以直接用at /dev/ttyx 運(yùn)行
運(yùn)行at
root@SUN:~# at /dev/ttyUSB0
ATI
AirM2M_Air724UG_V401876_LTE_AT
OK
審核編輯:湯梓紅
評論
查看更多