8月 272014
 

使用 bladeRF 板卡时我们会遇到两个“镜像”:固件 (firmware) 镜像与 FPGA 镜像。二者是两个不同的概念。但是业界叫法不一,有时候会把二者混为一谈。一般而言,固件指的是嵌入到硬件设备中的软件,存放在只读存储器 (ROM) 或者闪存 (flash) 中,一般不易修改,修改的操作称为“刷新”(flashing)。固件这个名词最初和微代码相关,不过 bladeRF 里源代码是嵌入式 C 程序。FPGA 全名为可编程门阵列,其门电路、寄存器连接可以编程重构,其源程序一般是硬件描述语言 (HDL),通过综合 (synthesis) 等步骤得到二进制文件。在 bladeRF 板卡上,FPGA 只是一块 Altera 芯片。在没有内置非挥发存储时,FPGA 镜像需要每次上电时重新加载,bladeRF 就是这种情况。所以在拿到板卡时,上面已有固件,但还没有 FPGA 镜像。下面本文会具体说明在使用 bladeRF 时如何刷新固件、加载/更新 FPGA 镜像、以及如何自动加载 FPGA 镜像。注意,有时为了避免混淆,会称 FPGA 镜像为 FPGA 比特流 (bitstream),或者 FPGA 配置(因为它就是配置了门电路等组件的连接)。

刷新固件

注意:刷新固件前请先取消 FPGA 自动加载,以避免可能的冲突。FPGA 自动加载的细节参见下文。

Nuand 官方提供固件的源码,我们可以自行编译,不过这需要一套嵌入式开发工具链。Nuand 也提供构建好的固件镜像,可以直接下载使用。要刷新固件,只需在命令行执行:

bladeRF-cli -f bladeRF_fw_vX.Y.Z.img -v verbose

其中 X.Y.Z 为具体的版本号。命令完成后,需要断电重启了 bladeRF。然后可以用 bladeRF-cli 工具检查:

$ bladeRF-cli -e version

  bladeRF-cli version:        0.11.1-git-c631100
  libbladeRF version:         0.16.2-git-c631100

  Firmware version:           1.7.1-git-ca697ee
  FPGA version:               Unknown (FPGA not loaded)

看下其中 Firmware version(固件版本)是否更新。

事实上,还有另外一种刷新固件的方法,是通过进入设备的启动加载 (Bootloader) 模式(类似 Android 的 Recovery),输入一些命令完成的。不过这种方式步骤繁琐,一般不推荐使用,建议在上述简单方法遇到错误时考虑采用。具体步骤参加维基

加载 FPGA 镜像

注意到上面的示例中,FPGA version(FPGA 版本)显示为 Unknown(未知),FPGA 未加载。目前 bladeRF 使用两种 FPGA。要加载正确的 FPGA 镜像,首先需要确定手头 bladeRF 板卡的 FPGA 尺寸。它可以根据当初购买的价格判断,但更靠谱的方法是使用命令行查看:

$ bladeRF-cli -i
bladeRF> info

  Serial #:                 4f977f01eec48f5068c2ee3aeba41ba9
  VCTCXO DAC calibration:   0x8b63
  FPGA size:                40 KLE
  FPGA loaded:              yes
  USB bus:                  4
  USB address:              5
  USB speed:                SuperSpeed
  Backend:                  libusb
  Instance:                 0

交互模式下用 info 命令,或者直接在命令行下 bladeRF-cli -e info,在输出中寻找 FPGA size,就可以看到 FPGA 尺寸信息。这里示例显示板卡使用 40 KLE FPGA。事实上,FPGA 尺寸还可以通过查看 FPGA 芯片上的 EP4CExxxF23C8N 字样中 xxx 的部分来获得。

Nuand 官方提供了预先构建的 FPGA 镜像,免除用户手工编译之苦。40 KLE FPGA 对应 hostedx40.rbf 文件,以此类推。要加载 FPGA 镜像,只需使用命令 bladeRF-cli -l /path/to/fpga/file,或者交互模式下 load fpga /path/to/fpga/file,其中 /path/to/fpga/file 为 FPGA 镜像所在路径。FPGA 镜像成功加载后,板卡上的三个 LED 灯会亮起,交互模式下 version 命令可以看到 FPGA 版本不再是未知。

不过,正如前文所说,每次重新加电后,FPGA 镜像都需要重新加载。下面说下如何自动加载 FPGA 镜像。

自动加载 FPGA 镜像

bladeRF 维基上提供了两种自动加载 FPGA 镜像的方法。第一种方法基于主机软件,libbladeRF 在打开设备时,会在如下目录自动搜索合适的 FPGA 镜像:

  • $HOME/.config/Nuand/bladeRF/
  • $HOME/.Nuand/bladeRF/
  • /etc/Nuand/bladeRF/
  • /usr/share/Nuand/bladeRF/

只需将下载的 FPGA 镜像文件放在上述目录之一(没有可以新建之),即可实现 FPGA 镜像的自动加载。

另一种方式是将 FPGA 镜像写入设备的 SPI 闪存。这种方式的好处是写入后就不再依赖主机,从而可以实现脱机运行。不过这种方式比较慢,加载 x40 镜像需要大约 4 秒钟。注意绝对不要在加载完成,三个 LED 灯亮起前试图使用设备。要使用这种方式,需要执行下面命令:

bladeRF-cli -L /path/to/fpga/file

一般说来,如果没有脱机工作的需求,还是推荐第一种自动加载方法。

前面提到,刷新固件时最好取消自动加载。对于第一种方法,只需把 FPGA 镜像文件临时移走。第二种方法,则需要执行命令 bladeRF-cli -L X,以擦除写入的 FPGA 镜像。

致谢

本工作由星天科技赞助。

8月 102014
 

bladeRF 维基上介绍了在 Linux 系统上搭建 bladeRF 环境的步骤,不过原文是英文的,另外其中一些具体选择不尽合理。本文以 Fedora 系统为示例,提供一个中文版的 bladeRF 环境搭建指南,并着重介绍和维基上的不同点。比较可能有一定的时效性,但一些原则应该足够通用。本文的比较基准是当前的维基版本

安装依赖

维基上建议安装 “Development Tools” “Development Libraries” 两个软件包组,但我们只需要其中的一部分软件包,其中有些可能已经安装过了,而像 cvs 等并不必须。如果你像我一样有“洁癖”,不希望安装不需要的软件包,那么可以用如下的命令安装必须的依赖(未严格验证,在我这里绝大多数包都在之前安装过了):

sudo yum install git doxygen gettext glibc-devel ncurses-devel readline-devel zlib-devel boost-devel
sudo yum install libusbx libusbx-devel cmake wget gcc-c++

注意其中是 libusbx 而非 libusb,后者是 0.x 系列的版本,而非 1.x 系列。Debian/Ubuntu 系的用户会注意到软件包命名上的差异 (devel 而非 dev)。

维基上推荐安装 libtecla,以增强 bladeRF-cli 交互模式的编辑功能。不过 Fedora 软件源里目前还没有这个包,所以需要手动下载,解压缩,使用经典的 ./configure; make; sudo make install 三部曲安装。

构建 bladeRF

在终端下进入打算用来放置 bladeRF 源码的目录,用 git 将 bladeRF 的源码库克隆下来:

cd /path/to/bladeRF/directory
git clone https://github.com/Nuand/bladeRF.git

切换到源码目录中的 host 目录,创建一个 build 目录用来存放构建过程的中间文件。这种使用单独的构建目录的方式称为树外构建 (out of tree build),相对于直接在源码目录构建,好处在于生成的中间文件不会分散在源码目录里,方便清理,另外可以用多个构建目录构建出互不干扰的不同参数下的版本。之后切换到构建目录,然后就是标准的 cmake ..; make; sudo make install 三部曲了。注意这里 cmake 时启用了 INSTALL_UDEV_RULES 宏,使得安装时把 udev 规则文件也安装到系统中。

cd bladeRF/host/
mkdir build
cd build
cmake -DINSTALL_UDEV_RULES=ON ../
make
sudo make install

很遗憾的是这里安装的 udev 规则文件使用了 plugdev 群组,不是 Fedora 下的标准做法。可以参考之前的博文修改 udev 规则文件。

为了让新安装的 bladeRF 库文件可以被二进制文件使用,我们需要用 ldconfig 刷新系统动态库的缓存。上面的构建过程会将 bladeRF 安装到 /usr/local 下,而其中的库文件目录 /usr/local/lib{,64} 不在 ldconfig 的默认搜索路径里。所以我们可以将它们添加到 /etc/ld.so.conf 里。添加之后文件内容如下:

/usr/local/lib
/usr/local/lib64
include ld.so.conf.d/*.conf

之后,用 sudo ldconfig 刷新缓存即可。可以用 ldd /usr/local/bin/bladeRF-cli 命令检查 bladeRF 库文件是否被找到。连上 bladeRF 设备,用 bladeRF-cli -p 命令看下是否能够发现设备。更多操作见于另一个维基页

构建 GNU Radio 与 gr-osmosdr

通过上述步骤,就可以操作 bladeRF 板卡了。但是,要想便捷地为 bladeRF 开发软件无线电应用,最好再构建一下 GNU Radio 和 gr-osmosdr。GNU Radio 是一个开源的软件无线电开发平台,提供众多的信号处理模块和简单易用的图形界面开发环境。gr-osmosdr 适配 GNU Radio,为众多硬件板卡(除了 bladeRF 之外还有 HackRF 等)提供一个统一的软件接口。

GNU Radio 依赖比较多,编译安装相对麻烦,一般推荐使用 build-gnuradio 脚本。但是因为其中涉及到从网络下载诸多软件以及编译安装,效率受网速和电脑硬件性能限制,耗时较长。另外,脚本的健壮性不高,所以很容易中途退出。这个脚本很长,但实际上是把整个构建过程划分为几个步骤,放在几个函数里先后执行的。我建议阅读这个 Shell 脚本,每次运行其中的一步或几步,必要时手动完成一些配置。对于新手,这会是一个很好的通过阅读代码学习 Shell 编程的机会。

具体的构建步骤可以在维基或这里找到,这里就不再赘述。只是提几点注意事项:

  • 如果你像我一样,除了 bladeRF 之外,还会使用 Ettus 公司的 USRP 系列设备,那么记得先构建 UHD,然后构建 GNU Radio。
  • build-gnuradio 脚本在 cmake 时,有时用了树外构建,但有时又没用。建议始终用树外构建。
  • 编译 GNU Radio 时,并行 make (make -j N 其中 N 大于 1)时有时会编译失败(竞态条件?),直接 make 就可以正常编译通过,虽然速度会慢很多。什么?make 也会出错?那考虑换一个 git 提交重新编译,并向上游报 BUG 吧。

构建成功 GNU Radio 后,构建 gr-osmosdr 就显得小菜一碟了,标准的 cmake 构建三部曲,项目不大,编译过程也能很快完成。

全部构建完成后,可以使用如下命令用 bladeRF 看一下频谱,检验是否大功告成。其中 FPGA 映像可以从 Nuand 网站下载。此外,最新固件也可以从官网下载。

osmocom_fft -a bladerf=0,fpga=<your FPGA image> -s 2000000 -f 446000000

致谢

本工作由星天科技赞助。

12月 152013
 

最近我把个人资料迁移到了一个新笔记本电脑上,旧电脑不再使用了,需要清除上面的个人数据。旧电脑是 Windows XP 与 Linux (Fedora 19) 的双系统,个人资料在 Linux 下,所以任务是清空 Linux 系统,保留原有 XP 可用。

由于重要的数据都已导出,所以这给了我一次在实体机上尝试 rm -rf / 的绝佳机会。众所周知,这项操作需要 root 权限 (su/sudo),而且 GNU 的 rm 默认已不再允许在顶级根目录下这样做,所以真实的命令是:

sudo rm -rf --no-preserve-root /

我是在原 Linux 系统图形界面的虚拟终端里做此操作的。过了一会儿,突然虚拟终端不见了,桌面背景等都还在。在图形界面试图新建虚拟终端无效。于是我切到控制台终端,发现控制台一直是等待状态,没法登录。(猜想是相应的程序都没了。)切回图形界面后发现鼠标键盘失去响应,但桌面背景还在。此时已经做不了什么有意义的操作,于是按电源键关机了。

之后用 Live USB 开机登录,挂载硬盘分区,发现原 Linux 的文件并没有全删光,还残留若干空目录,也有非空目录下有残余文件,$HOME 下也有几个残余文件(视频目录里有东西!$HOME 下还留着一个 PDF 文档!),不过所剩无几。

不过我们知道,Linux 下的 rm 本质上是去掉文件系统中的链接 (unlink),硬盘上的数据并没有擦除。使用数据恢复工具还是有可能找回其内容的。要真正地清空硬盘分区,需要进行“低格”,即低层格式化。Linux 上的 dd 命令可以做到这一点。如下 /dev/sda7 是一个 Linux 分区,我们通过往上面写入全零 (/dev/zero) 来擦除数据(使用 /dev/urandom 写入随机数也是可以的)。

[liveuser@localhost~]$ sudo dd if=/dev/zero of=/dev/sda7 & pid=$!

注意其中用的是一个 & 号,意为放后台运行。后面将进程号赋值给 pid 变量,是为了后面可以方便地查询进度,毕竟受限于磁盘 IO,dd 对于几百 GB 的硬盘是很慢的。可以通过向 dd 命令发送 USR1 信号获取当前进度:

[liveuser@localhost ~]$ sudo kill -USR1 $pid
[liveuser@localhost ~]$ 512417+0 records in
512417+0 records out
262357504 bytes (262 MB) copied, 17.5086 s, 15.0 MB/s

由于耗时实在太长,我是晚上把电脑一直开着,第二天去看的结果。最终擦写完成后会显示类似下面的信息:

[liveuser@localhost~]$ dd: writing to ‘/dev/sda7’: No space left on device
210183058+0 records in
210183057+0 records out
107613725184 bytes (108 GB) copied, 8295.38 s, 13.0 MB/s

可见,这个 108 GB 的分区用了两个多小时才擦写完。类似地对每个 Linux 分区执行上述 dd 命令,即可把所有数据擦除干净。有人会建议多擦写几次(3次?)以更加确定数据不会被恢复。不管怎样,注意务必写对分区编号,不然把(未备份的)有用数据擦掉了就出大事了。(如果你要清空整个硬盘的话,注意把硬盘设备名弄对。)

清除数据的任务到此就宣告结束了。不过,对于双系统来说,正常的引导是通过 GRUB 来实现的,而 /boot 分区或文件在前面已经被擦除了,所以开机会进入 GRUB 的 rescue shell 中。我没有搞明白如何在这里引导进入 XP 系统,于是用 Windows 系统光盘恢复引导。由于手头没有 XP 安装盘,当时用的是一个 Server 2003 的安装盘。不过操作是一样的,这个文档里有详细说明。简单来讲,就是进入 Windows 安装盘修复模式后执行 fixmbr 命令。

2月 232013
 

SSH 登陆一台新主机时,会提醒我们检查主机密钥的指纹。 不过怎么查看主机密钥的指纹呢?用什么命令? 这个问题显然不是第一次被问到,一篇 2008 年的文章 就指出了答案: 在新主机上运行命令

ssh-keygen -l -f /etc/ssh/ssh_host_rsa_key

ssh-keygen 命令的 -l 选项指示打印公钥的指纹。-f 指定公钥文件。 对于 RSA、DSA 密钥而言,不必须指定公钥文件,命令会自动寻找匹配文件。

查看主机密钥的指纹的命令居然字面意思是生成密钥,的确不太直观。 无独有偶,我们还知道删除 SSH 密钥的命令叫 ssh-add。 SSH 的命令就是这样。

11月 242012
 

依赖关系

Octave 的依赖很多,有 blas, lapack 线性代数库,一堆 稀疏矩阵库 (Fedora 安装 suitesparse-devel),还有 ftgl, arpack, qrupdate 的 devel库, gperf 等。比较烦人的还依赖 texi2dvi (虽然不时本质依赖,但没有它 make 最后报错)。

Fedora 软件仓库里的 texi2dvi,依赖 texlive RPM。 最初想用 fake texlive 包的办法,但发现它依赖的 /usr/bin/texconfig-sys 在 texlive 虚假包中一句 Provides 解决不了。最终还是下载了官方的 texinfo.tar.gz 压缩包,./configure; make; make install 解决。 注意这样会重复安装 info 等工具。

Octave 三部曲

最新的代码版本中把早先 Octave Forge 里的 Java 支持整合进来了。 然而这使得我 make 时报错 jni.h not found 于是安装 java-1.6.0-openjdk-devel,重来,还是不行。 查看 config.log 文件发现 JAVA_CPPFLAGS 不对(至少对 Fedora 来说), 几经周折发现手动指定 JAVA_HOME 可以绕开这个问题:

./bootstrap
JAVA_HOME=/usr/lib/jvm/java ./configure
make -j 6
make check

其他

最初把 hg 仓库克隆到了笔记本电脑上,后来意识到这不行(编译太慢),于是 转移到台式机上。发现可以建立一个文件夹 hg init 后,在源端使用 hg push。 不用担心 bare repo 的问题,hg 只会更新 .hg/ 下的东西,需要检出时 hg update 即可。

3月 312012
 

我们知道,引用其他人的东西需要注明出处,这包括论述文字也包括图片、视频等。然而互联网上的许多图片中并没有出处、作者等信息,需要手工加注。一般来讲,我们可以在图片外使用独立的文件记录下这些引用信息,不过这着实原始,而且可能使我们的图片文件夹显得混乱。这里说一种不同的方法,通过在图片中嵌入 EXIF 信息来达到记录引用来源的目的。由于 EXIF 算是个标准,而且是内嵌在原文件中,所以应该是个更好的选择。

EXIF 基础知识参见维基

这里使用的工具软件是 exiftool,它是一个 Perl 模块,同时提供了命令行程序。Fedora 下可以用命令 yum install perl-Image-ExifTool 安装。

具体的加入原始链接的操作示例如下:

exiftool -ArtworkSource='http://bloggersalchemy.com/sopa/' stop-sopa-pipa.jpg

之后可以用下面命令查看:

exiftool -ArtworkSource stop-sopa-pipa.jpg

另外,使用

exiftool -a -u -g1 stop-sopa-pipa.jpg

可以查看完整的内嵌信息。这条命令出自 exiftool(1) 的手册页的示例部分,更多请自行 man exiftool 之后搜索 examples

注意上面的 ArtworkSource 其实是 XMP 中的一个标签,我最初想使用 IPTC 下的 source 标签来存储原始链接。后来发现 source 的值是个长度为 0—32 的字符串(包括最后的 NULL 结束符)着实有限,它的本义也并非存储出处信息(参考指南)。另外 IPTC 算是古老陈旧了,新的 IPTCCore 规范已经使用 XMP 格式。你可能会问这些标签名字从何得知,答案是可以看 Image::ExifTool::TagNames(3pm) 的手册页 🙂

1月 222012
 

折腾 readline 时发现了几个问题。

当使用到上下左右箭头、PageUp/PageDown 等特殊键时,只能考虑用其 key sequence。怎么知道这个 sequence 呢?有两种方式,一是先按 Ctrl-v,然后按下未知sequence的键或键组合,如 Ctrl+UpArrow,这时对应的 sequence 会显示出来,

这其实是调用 bash readline 的 quote-insert 功能/命令。另一种方式是使用 read 命令(shell built-in),然后输入位置的键组合,然后其 sequence 也会打印出来。之后就可以写到 ~/.inputrc 里面了。这个要感谢这里的介绍

Ctrl-u 不能被可靠地重新绑定。因为它是底层 TTY 的编辑字符,bash 会将其绑定到对应的 readline 操作 unix-line-discard 上。参考 这个缓存。当初想重新绑定它是因为 bash 的手册页里示例将其绑定到了 universal-argument 自己也想这样做。后来想曲线救国,绑定到 Ctrl-i 上,然而 Ctrl-i 即 TAB,容易引起干扰。后面又试了 Ctrl-Meta-u,还是不行,于是作罢,安安心心用 Alt+数字的方式给 readline 命令输数字参数得了。

折腾下来的自定义 ~/.inputrc 文件,于是乎也没多少内容:

$ cat .inputrc
# Prev PageUp
"\e[5~": history-search-backward
# Next PageDown
"\e[6~": history-search-forward
# Write the string.
"\C-o": "> output"

# SEE ALSO
# http://code.google.com/p/iterm2/wiki/Keybindings#Escape_sequence_exploration
# You will learn that to get the key sequences of particular key stroke,
# use Ctrl+V (quoted insert) or read shell built-in.
# <Ctrl>+<Left arrow>
"\e[1;5D": backward-word
# <Ctrl>+<Right arrow>
"\e[1;5C": forward-word

# kill backward to the beginning
"\C-j": unix-line-discard

其实,有一些(许多?) readline 内置的键绑定也挺有趣,可能还很有用。例如 C-t, M-t 用来转置(翻转)两个字符或单词的前后位置。不过能否记住且熟练,实在不好说。