本文主要内容是如何将Raspberry Pi配置成一个具备路由功能的开发机。虽然网上已经有很多文章类似文章,但是我发现即便是完全按照步骤操作还是会遇到很多麻烦,例如:无线网卡驱动问题、路由自动启动问题、SD卡的读取问题等等。所以写此篇文章与大家分享一下经验,当然也欢迎大家提出问题,共同进步。:)
最近,入手了风靡全球的Raspberry Pi。这个设备真是一个不错的玩具,可以用你的智慧在上面实现很多非凡的想法和创意。搜索一下就会发现已经涌现出很多有趣的创意。而至于我入手的原因,主要为了能够利用长途路上的空闲时间进行web应用的移动式开发,像nodejs、ruby、html5、websocket、webgl。所以我将这个小Pi做成一个路由器兼linux开发机,然后用Android移动设备(本人屌丝无Apple设备)通过Secure Shell Client(强力推荐ConnectBot,其Google Play链接)进行开发,在移动设备的浏览器上进行测试。^_^
好了,我们开始吧。
第一步,设备清单,装配
本人购买的是一个四合一套装版,包括Raspberry Pi(Model B,Made In UK)、透明亚克力外壳(需手动拼装)、一张SD卡(4G,Class 4)、HDMI连接线,通过ICKey.cn购买(因为Pi官网提到了这个商家,不过它的新套餐居然更便宜了,而且感觉配件更实用,真的很无语),当然也还有很多其它渠道,如亚马逊、淘宝或者海外代购。其实Pi本身的价格虽然不高,但是随着功能的扩展和模块的添加,最后的价格也不会便宜。就拿我来讲,还要专门购买了一个无线网卡(TP-LINK TL-WN725N)。
在拿到货后先将外壳和线路板拼装起来,如下图,是手动拼装好后的Pi:
ps:据其他网友讲拼这个外壳的时候还是要手轻些,以免掰折卡口。
第二步,准备SD卡和系统
从Raspberry Pi官网下载系统镜像压缩包,由于个人平时使用ubuntu,所以就选用同样是基于Debian的Raspbian(其它系统并不了解)。下载完成后解压得到一个img文件,按照如下方法将该系统镜像写入SD卡中。
对于linux用户:
将SD卡与PC链接,通过如下命令写入系统。这个过程比较长,请耐心等待。
ddif=*raspbian镜像文件名*.img of=*设备路径*
ps:请根据自己的使用环境替换*raspbian镜像文件名*和*设备路径*
对于windows用户:
下载Win32DiskImager工具,解压后运行。同样将SD卡与PC链接,选择系统镜像,选择SD卡盘符,点击Write,将会把系统写入SD卡。
ps:这里与官网所描述没什么区别。更全面的讲解请参考:http://elinux.org/RPi_Easy_SD_Card_Setup
在做好系统后不要着急去启动,因为如果显示器分辨率比较低的话,你会发现屏幕无法显示所有内容。所以为了能够得到一个完整的显示,需要配置一下相应显示器的分辨率。
将写入系统的SD卡重新连接到PC上,你可以看到一个fat格式的盘符(ubuntu和windows都可以识别出来)。找到并打开该盘符下的config.txt文件,把其中的hdmi_group设置改为2,hdmi_mode设置改为11,去掉这两项前的“#”(如果有的话)。这个设置表示显示器的分辨率和频率分别为800×600和75Hz。当然还有很多其它分辨率可用,具体数值配置请参考此网址:http://elinux.org/RPi_config.txt。
第三步,首次启动和配置Pi,修复SD卡文件系统,更新系统
通电之前要将SD卡和无线网卡插入Pi,连接一根网线(我们需要通过网络更新系统和安装驱动),连接一个USB键盘作为输入设备,通过HDMI线连接显示器作为输出设备。使用当前很常见的一种电源线(Micro USB Power)给Pi供电。注意:Pi并没有电源开关,链接电源启动,拔掉电源则关机。
通电后系统将会进入首次启动配置页面(如果以后还想进行这样的配置运行‘sudo raspi-config’即可),请进行下列操作:
选择expand_rootfs,将系统容量进行扩展
选择boot_behaviour,将启动方式设置为console
选择change_pass,设置用户pi的密码。这个pi用户就是一个管理员账户
选择ssh,启用ssh
选择change_timezone,设置时区
完成以上5个配置后,在主菜单中选择Finish,即完成首次启动前的配置。
刚开始使用Pi时,总是会发生磁盘分区问题,导致一出现问题就重写SD卡。经过一番搜索后发现需要通过fsck对SD卡文件系统进行一次修复。估计是第一次启动的扩充系统容量操作会导致分区大小错误,从而出现后续写入的文件在重启后无法读取。
将SD卡重新链接到ubuntu上,运行如下脚本命令:
sudofsck.ext4 -p /dev/sdd2
好了,至此我们的SD卡就已经准备完毕。
重启系统后通过用户名pi和密码(如果没有设置新密码则为raspberrypi)进入系统。在命令行模式下,通过如下命令更新系统:
sudoapt-get update && sudoapt-get upgrade
一段漫长的更新后,你就已经可以使用最新版的Raspberry Pi了。
第四步,编译安装无线网卡驱动(TP-LINK TL-WN725N 2.0)和软AP程序
由于当前Raspbian系统并没有提供TL-WN725N 2.0的驱动,所以在启动后无法识别到wlan设备。在这里要感谢《用raspberry-pi制作无线路由过程的札记2-编译8188eu芯片的无线网》和《raspberry pi 入手小记》文章的作者,感谢他们提供了编译安装TL-WN725N 2.0驱动和该网卡的软AP程序的方法,具体操作请转至这两篇文章。
如果你不想编译,后面‘相关链接’部分有已经编译好的驱动和软AP程序下载链接。然后通过下面命令安装该驱动:
sudoinstall-p -m 644 8188eu.ko /lib/modules/3.6.11+/kernel/drivers/net/wireless/
sudo/sbin/depmod-a 3.6.11+
第五步,设置路由
此处要感谢《树莓派上手实战之把Raspberry Pi 配置成无线路由器》,这篇文章描述了如何使用hostapd和isc-dhcp-server将Pi制作成一个软路由。使用TL-WN725N 2.0无线网卡的用户要记住安装好hostapd后,请用我们上一步所编译好的hostapd和hostapd_cli覆盖/usr/sbin目录下的文件。完成文中所述操作后,平板或者手机就应该可以通过Pi来访问网络了。
这时会出现一个使用问题,每次开机后都要通过命令来开启路由功能。由于软路由的开启是两个模块组成的,所以最好的解决方法是自制一个启动服务脚本,然后使用update-rc.d来控制。我的启动脚本raspi-router,其内容如下:
#!/bin/sh
#
#
### BEGIN INIT INFO
# Provides: raspi-router
# Required-Start: $remote_fs $network $syslog
# Required-Stop: $remote_fs $network $syslog
# Should-Start: $local_fs slapd $named $network
# Should-Stop: $local_fs slapd
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Router Server in Raspberry Pi
# Description: Activite hostapd and isc-dhcp-server in Raspberry Pi
### END INIT INFO
PATH=/sbin:/bin:/usr/sbin:/usr/bin
case"$1"in
start)
service hostapd start
echo"Set the address of wlan0 to 192.168.91.1"
ifconfigwlan0 192.168.91.1
service isc-dhcp-server start
;;
stop)
service hostapd stop
service isc-dhcp-server stop
;;
restart | force-reload)
service hostapd restart
echo"Set the address of wlan0 to 192.168.91.1"
ifconfigwlan0 192.168.91.1
service isc-dhcp-server restart
;;
status)
service hostapd status
service isc-dhcp-server status
;;
*)
echo"Usage: $0 {start|stop|restart|force-reload|status}"
exit1
esac
exit0
注意:第23行和33行的192.168.91.1,这个地址是Pi作为路由的ip地址。如果你的有所不同,请自行更改。
将该脚本放到/etc/init.d目录下,运行以下脚本命令,将会安装并运行rcconf:
sudoapt-get installrcconf
sudorcconf
选择rcconf界面中的raspi-router并确定,如下图:
第六步,完成,测试
好了,按照上面所描述的方法和注意事项,你应该可以得到一个路由器兼开发机。通过手机或平板上的ssh应用程序即可访问该路由,并进行web应用开发。如果配上随身电源,那么不管走到哪里都可以连接到Pi上,访问你的web应用服务。在我的Pi上就运行着用nodejs+websocket开发的聊天服务,这样即便是在旅途中,周围的朋友都可以访问这个路由进行沟通(似乎有点多余:))。当然也可以做成文档服务器、游戏服务器、微社交服务器等等,就可以真正的实现移动办公、移动游戏、移动交友(瞎掰了)。
结束语
文中如有错误和问题,欢迎指正,欢迎咨询、欢迎交流、欢迎留言。
最后附一张截图,启动后的Pi:
用Raspberry Pi制作无线路由过程的札记2-编译8188eu芯片的无线网卡驱动和hostap
当时在采集RPi的配件时,是依据elinux.org上RPi_VerifiedPeripherals的信息。上面所列出的可兼容硬件都是RPi玩家亲试的。选择TP-LINK TL-WN725N USB无线网卡的原因就是上面写着“TL-WN725N Works out of the box on Raspbian 2012-12-16 without a powered USB hub.”。当时也有考虑过EDUP N8508,但因为它需要接上有源USB HUB来保证供电,而我不想在用作无线路由时还要带着一个USB HUB,所以就选择了TL-WN725N。
但买回来的TL-WN725N插入到RPi却无法驱动。ifconfig -a
没有看到wlan0。无论是在Raspbian还是Arch Linux ARM下都无法使用。
[root@alarmpi ~]# lsusb
复制代码
的显示是:
Bus001Device002: ID 0424:9512StandardMicrosystemsCorp. LAN9500 Ethernet10/100Adapter
Bus001Device001: ID 1d6b:0002LinuxFoundation2.0 root hub
Bus001Device003: ID 0424:ec00 StandardMicrosystemsCorp.
Bus001Device004: ID 0bda:8179RealtekSemiconductorCorp.
复制代码
和网上一些论坛里贴出的不一样:
Bus001Device008: ID 0bda:8176RealtekSemiconductorCorp. RTL8192CU 802.11n WLAN Adapter
复制代码
连具体的芯片型号也没识别出来。也在论坛问一下,有人说是供电的问题。但我也试过插到有源的USB HUB里,lsusb
得到的结果一样。不过,发现一个问题是网上贴出的lsusb
结果中的USB ID和我的不一样,网上的是8176,而我的是8179。于是google一下才发现,这个型号的网卡分v1和v2,v1(即8176)的芯片是8192cu,而v2(即8179)的芯片是8188eu。于是到Realtek的官网找了一下,没有8188eu。但感觉TL-WN725N两个版本的芯片应该是差不多,否则厂家不可能这样替换,而价格和功能的说明却没改。所以就下了Realtek官网上8192cu的驱动下来编译试试。结果不行,ifconfig -a
和lsusb
显示的结果一样,而lsmod
中却能看到新编译的8192cu驱动已经被内核加载了,而旧的rtl8192cu也被禁止了。在苦恼之际,随便看了一下8192cu驱动中的文档,却发现有提到RTL8188eu,但在驱动的发行说明中的支持芯片列表中却没看到RTL8188eu。难道是官方还没有提供8188eu的Linux驱动,而google“8188eu linux driver”之后发现有很多8188eu的Windows驱动,却没有Linux的。而在某论坛中发现有人也是用v2版的,而他在一个国产的Android智能电视棒的Linux系统源码中找到了8188eu的驱动代码:https://github.com/Red54/linux-shumeipai2/tree/sunxi-3.0/drivers/net/wireless/rtl8188eu。看了一下其github中的提交备注和对比了一下它和8188cu的源码,发现这个驱动源码应该是在8192cu的基础上修改的,而不是官方发布的。不过管不了那么多了,下载下来试试。
由于在编译安装驱动的过程,要用到gcc编译工具链,还有一些Linux的实用工具和用unzip解压驱动源码包,所以先要通过pacman安装它们:
[root@alarmpi ~]# pacman -S util-linux unzip base-devel
复制代码
安装好上述的软件包后,最好重新启动一下系统:
[root@alarmpi ~]# reboot
复制代码
在编译之前,需要修改驱动源码目录里Makefile
文件中的编译选项。在Makefile
里可以找到如下的目标编译平台开关宏。可见其中的默认配置是i386平台:
...
CONFIG_PLATFORM_I386_PC = y
CONFIG_PLATFORM_ANDROID_X86 = n
CONFIG_PLATFORM_ARM_S3C2K4 = n
CONFIG_PLATFORM_ARM_PXA2XX = n
...
复制代码
这里没有RPi的BCM2708平台配置,所以需要自行添加。首先在将CONFIG_PLATFORM_I386_PC
改为n
,并在下面添加RPi的目标编译平台开关宏,修改后的代码如下:
...
CONFIG_PLATFORM_I386_PC = n
CONFIG_PLATFORM_BCM2708 = y
CONFIG_PLATFORM_ANDROID_X86 = n
CONFIG_PLATFORM_ARM_S3C2K4 = n
CONFIG_PLATFORM_ARM_PXA2XX = n
...
复制代码
接下来是创建新增的目标编译平台配置项。还是在Makefile里,继续往下找,可以看到:
...
ifeq ($(CONFIG_PLATFORM_I386_PC), y)
EXTRA_CFLAGS +=-DCONFIG_LITTLE_ENDIAN
SUBARCH := $(shell uname -m | sed -e s/i.86/i386/)
ARCH ?= $(SUBARCH)
CROSS_COMPILE ?=
KVER := $(shell uname -r)
KSRC :=/lib/modules/$(KVER)/build
MODDESTDIR :=/lib/modules/$(KVER)/kernel/drivers/net/wireless/
INSTALL_PREFIX :=
endif
ifeq ($(CONFIG_PLATFORM_TI_AM3517), y)
EXTRA_CFLAGS +=-DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_SHUTTLE
CROSS_COMPILE := arm-eabi-
KSRC := $(shell pwd)/../../../Android/kernel
ARCH := arm
endif
...
复制代码
在ifeq ($(CONFIG_PLATFORM_I386_PC), y)...endif
和ifeq ($(CONFIG_PLATFORM_TI_AM3517), y)
之间添加CONFIG_PLATFORM_BCM2708
的编译配置参数,即添加如下的代码:
...
ifeq ($(CONFIG_PLATFORM_BCM2708), y)
EXTRA_CFLAGS +=-DCONFIG_LITTLE_ENDIAN
ARCH := arm
CROSS_COMPILE :=
KVER := $(shell uname -r)
KSRC :=/lib/modules/$(KVER)/build
MODDESTDIR :=/lib/modules/$(KVER)/kernel/drivers/net/wireless
INSTALL_PREFIX :=
MODULE_NAME :=8188eu
endif
...
复制代码
解释一下这些编译参数的含意:
-
EXTRA_CFLAGS
:附加编译选项,可用值如下:CONFIG_BIG_ENDIAN
和CONFIG_LITTLE_ENDIAN
是大端存储械和小端存储模式。两种存储模式在ARM上都支持,而默认是小端存储,所以这里选择了CONFIG_LITTLE_ENDIAN
CONFIG_MINIMAL_MEMORY_USAGE
是指定以小内存分配模式。为了在性能较强的平台上获得较好的性能,驱动会分配大尺寸的连续内存空间作为TX/RX的IO缓冲区。这种分配模式在嵌入式平台中可能导致内存分配失败,可以通过定义此项来避免这个问题。考虑到RPi的内存比较大,所以不使用小内存分配模式,故此项忽略CONFIG_PLATFORM_ANDROID
是用在没有定义CONFIG_ANDROID
宏的旧版本Android平台上强制生成Android代码的情况
ARCH
:目标编译平台。RPi的BCM2853是ARM架构,填“arm”CROSS_COMPILE
:指定交叉编译工具链。直接在RPi上编译,不需要指定此项KVER
:内核版本。通过shell的uname -r
获取即可KSRC
:内核源代码路径。填/lib/modules/$(KVER)/build
MODDESTDIR
:模块目标目录。这个选项是用于指定编译好的驱动模块的安装路径,填/lib/modules/$(KVER)/kernel/drivers/net/wireless
。其实也可以不填此项,等编译完成后将编译好的.ko
文件复制到指定的目录也可以,并使用depmod -a
命令将编译好的驱动模块安装到内核中INSTALL_PREFIX
:模块安装目录。这个可以不填,但如果编译出现的模块有多个文件,也可以设置专门的目录用于存放。如果填写了此项,那些模块的安装目录就会变成:MODDESTDIR/INSTALL_PREFIX
,而不是MODDESTDIR
了MODULE_NAME:模块名称。最后编译出来的驱动文件的名称就是此名称加
.ko
。如果没有设置此项,则默认为8188cu
,即编译好的驱动文件名称为8188eu.ko
把上述的内容都修改好后,保存Makefile
文件,就可以用
[root@alarmpi rtl8188eu]# make && make install
复制代码
来编译及安装驱动模块。
由于模块没有编译进内核中,而是作为附加模块来编译的,所以要让系统在启动的时候自动加载它才可以使用。这里使用systemd的方法来设置,在/etc/modules-load.d目录下创建一下模块加载的配置文件(如8188eu.conf
),在配置文件里写入驱动文件的名称,但不要带.ko
,如8188eu
即可。
所有这些完成后,重新启动系统就可以使用TL-WN725N了。lsusb
依然没有显示其芯片型号,不过ifconfig -a
可以看到wlan0了。
正在兴奋之余,安装了hostap:
[root@alarmpi ~]# pacman -S hostap
复制代码
,配置好/etc/hostapd/hostapd.conf
,却提示nl80211驱动不兼容此网卡。弄了几天才找到可用的驱动,好不容易才让系统识别到无线网卡,现在又冒出一个问题。再一次绝望了!
在绝望之余,突然在8192cu的官方驱动包时看到有一个关于软ap的使用文档,便好奇地打开看看。发现里面关于启动软ap的步骤中的第5步是编译驱动包里的一个hostap工具。然后翻了翻其他pdf文档,在一个关于软ap模式特性的文档里讲到,托管网络模式需要hostap加上基于Realtek专用的871x驱动接口才可以启动。一下子豁然开朗了!原来这个系列的无线网卡不再使用老试的nl80211兼容驱动来打开软ap模式,而是需要Realtek专用的驱动来实现的。
于是,解压8192cu官方驱动包中的wpa_supplicant_hostapd/wpa_supplicant_hostapd-0.8_rtw_20120803.zip
,切换到其中的hostapd
目录,执行make
进行编译。完成后用编译好的hostapd
覆盖掉/usr/bin/hostapd
,再将/etc/hostapd/hostapd.conf
里的driver
项改为rtl871xdrv
,通过
[root@alarmpi ~]# hostapd /etc/hostapd/hostapd.conf
复制代码
启动软ap。
用手机搜索一下,找到刚启动的软ap了。
在上面提到的软ap模式特性文档中说明了这个专用的ap驱动只支持CCMP安全模式和WPA-PSK认证模式,所以在/etc/hostapd/hostapd.conf
中最好将wpa_key_mgmt
设置为WPS-PSK
,和将wpa_pairwise
设置为CCMP
。其他的配置参数请见具体的说明文档及样例配置文件中的注释。
最后,还可以将hostapd设置成系统启启动时自动启动的服务项,这样就不用每次启动系统都要手工加载hostapd了:
[root@alarmpi ~]# systemctl enable hostapd
复制代码
弄了接近3天,终于弄好了软ap了。这里提供已经修改好Makefile的8188eu驱动源码、Realtek专用的hostapd源码及软ap模式的相关说明文档的归档文件,方便有需要的朋友下载使用。
后记:使用内核没有提供驱动的硬件有个不方便的地方——升级内核的时候需要重新编译驱动。而我是把RPi作为无线路由用的,虽说没必要频繁升级内核,但我又不满足于RPi只做无线路由,还打算玩其他东西。最后还是决定更换无线网卡。年后进了一个Tenda W311MI(主控是Ralink RT5370),RPi的固件中直接提供了驱动,省了手工编译安装驱动的麻烦。而且该网卡的驱动是基于mac80211的,可以使用nl80211驱动的hostapd,可以直接使用从更新源直接安装的hostapd。不过还有点不足——无法打开wps,不知道是网卡不支持(网卡的盒子还写着支持的),还是hostapd的问题。算了,又岂能事事尽如人意呢!反正放家里用,又不开802.11n,出到外面连信号都没了,还管他安不安全了。