谷动谷力

 找回密码
 立即注册
查看: 3102|回复: 0
打印 上一主题 下一主题
收起左侧

【openwrt应用开发】openwrt交叉编译自己的应用程序入门

[复制链接]
跳转到指定楼层
楼主
发表于 2023-7-31 16:03:45 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 sunsili 于 2024-4-11 10:32 编辑

【openwrt应用开发】openwrt交叉编译自己的应用程序入门
类似minicom串口终端at应用程序开发

准备

开发板: SUN7628 (MT7628 ROM:32MB RAM:128MB)
openwrt源码: OpenWrt Chaos Calmer(CC) 15.05.1 r49396
前提: 编译Openwrt源码包通过

OpenWrt应用程序开发方式

OpenWrt上面应用程序开发有两种方式:
1、利用OpenWrt SDK,
2、利用OpenWrt源码。
其实过程都差不是很多。源码会直接生成可执行程序的demo,SDK只生成ipk包,进行opkg安装。

在编译根目录下会有一个dl的目录,这个目录其实是“download”的简写,在编译前期,需要从网络下载的数据包都会放在这个目录下,这些软件包的一个特点就是,会自动安装在所编译的固件中,也就是我们make menuconfig的时候,为固件配置的一些软件包。如果我们需要更改这些源码包,只需要将更改好的源码包打包成相同的名字放在这个目录下,然后开始编译即可。编译时,会将软件包解压到build_dir目录下。

OpenWrt应用程序开发

很多入门教程都写hellowrold, 写helloword没什么实际用途,本次制作一个类似minicom串口终端, 我命名为at, minicom太大,我们自己写的at非常小,使用简单方便,相信大家用后会爱不释手。

下面我们利用OpenWrt源码开发at:
1、进入package目录,创建软件目录
  1. #cd openwrt/package
  2. #mkdir at
复制代码



2、进入test目录,创建Makefile文件和代码路径
├── at
     ├── Makefile
     └── src
          ├── at.c
          └── Makefile

该Makefile基本内容格式都差不多,可参照以下进行修改
  1. #
  2. # Copyright (C) 2009-2010 Jo-Philipp Wich <xm@subsignal.org>
  3. #
  4. # This is free software, licensed under the GNU General Public License v2.
  5. # See /LICENSE for more information.
  6. #
  7. # 导入通用编译规则
  8. include $(TOPDIR)/rules.mk

  9. # name和version用来定义编译目录名$(PKG_BUILD_DIR)]
  10. PKG_NAME:=at
  11. PKG_VERSION:=1.0
  12. PKG_RELEASE:=1
  13. #PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)  # 也可以直接定义编译目录名,代替默认的目录名

  14. # 导入包定义
  15. include $(INCLUDE_DIR)/package.mk

  16. # 包定义:定义我们的包在menuconfig中的位置
  17. # Makefile中的define语法可以理解为函数,用于定义命令集合
  18. define Package/at
  19.   SECTION:=utils
  20.   CATEGORY:=Base system
  21.   TITLE:=at, uart at from example.
  22. endef

  23. # 包描述:关于我们包的更详细的描述
  24. define Package/at/description
  25.   A simple at example for uart utils, my first openwrt package example.
  26. endef

  27. # 编译准备. 必须使用tab缩进,表示是可执行的命令
  28. define Build/Prepare
  29.         echo "Here is Build/Prepare at"
  30.         mkdir -p $(PKG_BUILD_DIR)
  31.         cp ./src/* $(PKG_BUILD_DIR)/
  32. endef

  33. # 安装
  34. define Package/at/install
  35.         $(INSTALL_DIR) $(1)/usr/bin
  36.         $(INSTALL_BIN) $(PKG_BUILD_DIR)/at $(1)/usr/bin
  37. endef

  38. # 这一行总是在最后
  39. $(eval $(call BuildPackage,at))
复制代码

注意以上凡是命令行,必须以tab开头,否则会出现Makefile:3: *** missing separator.  Stop.

#mkdir  src

3、进入src目录,创建相关源文件

#cd src

创建源文件at.c,如下
  1. /*
  2. * at
  3. * Like minicom
  4. * Usage: ./at /dev/ttyx
  5. * lojam
  6. * http://bbs.sunsili.com
  7. */

  8. #include <unistd.h>
  9. #include <stdio.h>
  10. #include <sys/stat.h>
  11. #include <fcntl.h>
  12. #include <string.h>
  13. #include <stdlib.h>
  14. #include <errno.h>
  15. #include <signal.h>
  16. #include <termios.h>
  17. #include <sys/types.h>
  18. #include <poll.h>

  19. int ttyfd;
  20. int stdout_changed = 0;
  21. int tty_changed = 0;
  22. struct termios stdout_tio;
  23. struct termios tty_tio;

  24. void restore_tio()
  25. {
  26.     if(stdout_changed)
  27.     {
  28.         stdout_tio.c_lflag |= ECHO;
  29.         tcsetattr(STDIN_FILENO, TCSANOW, &stdout_tio);
  30.     }
  31.     if(tty_changed)
  32.     {
  33.         tcsetattr(ttyfd, TCSANOW, &tty_tio);
  34.     }
  35. }

  36. void int_handler(int signum)
  37. {
  38.     close(ttyfd);
  39.     exit(EXIT_SUCCESS);
  40. }


  41. int main(int args, const char *argv[])
  42. {
  43.     char readBuf[256];
  44.     const char *ttyPath = argv[1];
  45.     const char *atCommand = argv[2];
  46.     struct termios tio;
  47.     int ret;

  48.     if(args !=2 )
  49.     {
  50.         fprintf(stderr, "Usage: ./at /dev/ttyx\n");
  51.         exit(EXIT_FAILURE);
  52.     }

  53.     atexit(restore_tio);

  54.     ttyfd = open(ttyPath, O_RDWR | O_NOCTTY | O_NDELAY);

  55.     if(ttyfd < 0)
  56.     {
  57.         perror("open");
  58.         exit(EXIT_FAILURE);
  59.     }

  60.     signal(SIGINT, int_handler);
  61.    
  62.     ret = tcgetattr(ttyfd, &tio);

  63.     if (ret == -1)
  64.         {
  65.                 perror("tcgetattr");
  66.                 exit(EXIT_FAILURE);
  67.         }
  68.         memcpy(&tty_tio, &tio, sizeof(struct termios));
  69.         tio.c_iflag = 0;
  70.         tio.c_oflag = 0;
  71.         tio.c_cflag = CS8 | CREAD | CLOCAL;
  72.         tio.c_cflag &= (~CRTSCTS);
  73.         tio.c_lflag = 0;
  74.         tio.c_cc[VMIN] = 1;
  75.         tio.c_cc[VTIME] = 0;
  76.         if (cfsetospeed(&tio, B115200) < 0 || cfsetispeed(&tio, B115200) < 0)
  77.         {
  78.                 perror("cfseti/ospeed");
  79.                 exit(EXIT_FAILURE);
  80.         }
  81.         ret = tcsetattr(ttyfd, TCSANOW, &tio);
  82.         if (ret == -1)
  83.         {
  84.                 perror("tcsetattr");
  85.                 exit(EXIT_FAILURE);
  86.         }
  87.         tty_changed = 1;

  88.         struct termios outio;
  89.         ret = tcgetattr(STDIN_FILENO, &outio);
  90.         if (ret == -1)
  91.         {
  92.                 perror("tcgetattr");
  93.                 exit(EXIT_FAILURE);
  94.         }
  95.         memcpy(&stdout_tio, &outio, sizeof(struct termios));
  96.         stdout_changed = 1;
  97.         outio.c_lflag &= ~ECHO;
  98.         ret = tcsetattr(STDIN_FILENO, TCSANOW, &outio);

  99.         int flags = fcntl(STDIN_FILENO, F_GETFL, 0);
  100.         fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);

  101.         struct pollfd fds[] = {
  102.                 {STDIN_FILENO, POLLIN, 0},
  103.                 {ttyfd, POLLIN, 0}
  104.         };

  105.         while (1)
  106.         {
  107.                 ret = poll(fds, sizeof(fds)/sizeof(struct pollfd), 0);
  108.                 if (ret == -1)
  109.                 {
  110.                         perror("poll");
  111.                         exit(EXIT_FAILURE);
  112.                 }
  113.                 if (fds[0].revents & POLLIN)
  114.                 {
  115.                         memset(readBuf, 0, sizeof(readBuf));
  116.                         ret = read(fds[0].fd, readBuf, sizeof(readBuf));
  117.                         if (ret < 0 && errno != EAGAIN)
  118.                         {
  119.                                 perror("read");
  120.                                 exit(EXIT_FAILURE);
  121.                         }
  122.                         if (ret > 0)
  123.                         {
  124.                                 strcpy(readBuf+ret-1, "\r\n");
  125.                                 // printf("%s", readBuf);
  126.                                 ret = write(ttyfd, readBuf, strlen(readBuf));
  127.                                 if (ret < 0)
  128.                                 {
  129.                                         perror("write");
  130.                                         exit(EXIT_FAILURE);
  131.                                 }
  132.                         }
  133.                 }
  134.                 if (fds[1].revents & POLLIN)
  135.                 {
  136.                         memset(readBuf, 0, sizeof(readBuf));
  137.                         ret = read(fds[1].fd, readBuf, sizeof(readBuf));
  138.                         if (ret == -1 && errno != EAGAIN)
  139.                         {
  140.                                 perror("read");
  141.                                 exit(EXIT_FAILURE);
  142.                         }
  143.                         printf("%s", readBuf);
  144.                 }
  145.         }

  146.         int commandLen = strlen(atCommand);
  147.         char *buf = (char *)malloc(commandLen + 3);
  148.         sprintf(buf, "%s\r\n", atCommand);
  149.         ret = write(ttyfd, buf, strlen(buf));
  150.         if (ret < 0)
  151.         {
  152.                 perror("write");
  153.                 exit(EXIT_FAILURE);
  154.         }
  155.         free(buf);

  156.         while (1)
  157.         {
  158.                 ret = read(ttyfd, readBuf, sizeof(readBuf));
  159.                 if (ret < 0 && errno != EAGAIN)
  160.                 {
  161.                         perror("read");
  162.                         exit(EXIT_FAILURE);
  163.                 }
  164.                 if (ret > 0)
  165.                         write(1, readBuf, ret);
  166.         }

  167.         return 0;
  168. }
复制代码

创建源文件的Makefile
  1. TARGET = at
  2. OBJS = at.o

  3. $(TARGET):$(OBJS)
  4.         $(CC) $(LDFLAGS) -o $@ $^

  5. %.o: %.c
  6.         $(CC) $(CFLAGS) -c [        DISCUZ_CODE_11        ]lt; -o $@

  7. .PHONY: clean
  8. clean:
  9.         rm -f $(TARGET) $(OBJS)
复制代码

编译

4、回到顶层目录
  1. make menuconfig
复制代码

Base system —>
             at

选中行按空格键我们刚刚创建的at。保存退出

单独编译at模块

  1. make package/at/compile V=s
  2. make[1]: Entering directory '/home/fan/openwrt_CC_mt76xx_omj_source'
  3. make[2]: Entering directory '/home/fan/openwrt_CC_mt76xx_omj_source/package/libs/toolchain'
  4. 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

  5. .........
  6. make[2]: Leaving directory '/home/fan/openwrt_CC_mt76xx_omj_source/package/at'
  7. make[1]: Leaving directory '/home/fan/openwrt_CC_mt76xx_omj_source'
复制代码


不出意外,就编译好了
也可以编译openwrt固件时编译,编译固件,参考:【openwrt】OpenWrt编译 – 说明-谷动谷力 (sunsili.com)

观察编译过程可以发现交叉编译工具为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/

编译成功后,
  1. #ls build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/at-1.0/at
  2. at.c  at.o  ipkg-ramips_24kec  Makefile
复制代码


编译openwrt打包进固件

直接make (-j8  需要电脑支持)
编译成功后
生成ipk安装好
  1. .......
  2. Generating index for package ./at_1.0-1_ramips_24kec.ipk  
  3. ......
复制代码

at应用程序存放位置
  1. 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包存放位置
  1. ls  bin/ramips/packages/base/
复制代码



可以找到 at_1.0-1_ramips_24kec.ipk

测试

单独编译的at模块



用scp拷贝at到开发板,执行就ok了
  1. scp build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/at-1.0/at root@192.168.3.125:/root
  2. root@192.168.3.125's password: #输入openwrt开发板密码
  3. at                                                                                    100%
复制代码

等待传输完成

ssh登录开发板(可以用可视化工具,如mobaxterm,点击可以查看用法)
ssh root@192.168.3.125
root@192.168.3.125's password:#输入openwrt开发板密码

BusyBox v1.23.2 (2023-07-31 09:34:21 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 #绿色的, 可执行的, root有执行权限
....

在开发板运行at测试一下, 我开发板开有一个Air724模块,用ttyUSB0端
Usage: ./at  /dev/ttyUSB0
运行加端口号即可
root@TJ:~# ./at /dev/ttyUSB0
ATI #发行AT指令

AirM2M_Air724UG_V401876_LTE_AT  #Air724模块 返回Air724模块软硬件相关信息

OK


同时ctrl+c 可以退出 at 应用

openwrt打包编译

用scp拷贝at_1.0-1_ramips_24kec.ipk到开发板
  1. scp ./bin/ramips/packages/base/at_1.0-1_ramips_24kec.ipk root@192.168.3
  2. .125:/tmp
  3. root@192.168.3.125's password:
  4. at_1.0-1_ramips_24kec.ipk                                                             100% 3108     3.0KB/s   00:00
复制代码


等待传输完成

安装at


在开发板上运行
  1. root@SUN:~# opkg install /tmp/at_1.0-1_ramips_24kec.ipk
  2. Installing at (1.0-1) to root...
  3. Configuring at.
复制代码


运行at (安装后,无论在何目录下,都不用加./ 加路径,可以直接用at /dev/ttyx 运行
  1. root@SUN:~# at /dev/ttyUSB0
  2. ATI

  3. AirM2M_Air724UG_V401876_LTE_AT

  4. OK
复制代码



烧录固件

用scp拷贝penwr升级固件k到开发板
  1. scp bin/ramips/openwrt-ramips-mt7628-mt7628-squashfs-sysupgrade.bin root@192.168.3.125:/tmp
  2. root@192.168.3.125's password:
  3. openwrt-ramips-mt7628-mt7628-squashfs-sysupgrade.bin                                  100% 8704KB   1.1MB/s   00:08
复制代码


开发板运行:
  1. sysupgrade -n -F /tmp/openwrt-ramips-mt7628-mt7628-squashfs-sysupgrade.bin
复制代码


详细说明openwrtl固件升级,请参考:openwrt怎么升级固件?使用命令sysupgrade实现openwrt升级固件-谷动谷力 (sunsili.com)

烧录后,at会存放在开发析的 /usr/bin目录下,不用安装,无论在何目录下,都不用加./ 加路径,可以直接用at /dev/ttyx 运行

运行at
root@SUN:~# at /dev/ttyUSB0
ATI

AirM2M_Air724UG_V401876_LTE_AT

OK


本帖被以下淘专辑推荐:

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|深圳市光明谷科技有限公司|光明谷商城|Sunshine Silicon Corpporation ( 粤ICP备14060730号|Sitemap

GMT+8, 2024-4-27 16:49 , Processed in 0.089203 second(s), 45 queries .

Powered by Discuz! X3.2 Licensed

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表