2013年

折腾RaspberryPi已经一段日子了,期间还因接错GPIO的线而报废了一个。重新入手了英国版后,却没再怎么玩了。

昨天搜索相关资料时,找到一个很简单的关机按钮方法(http://spaceblogs.org/flipdot/2013/06/shut-down-your-raspberry-pi-on-button-press-and-add-reset-function/)就是利用2.0版新增的P5接口,直接连上个开关,实现关机功能。根据该文章,还可以直接在P6上连个按钮,实现重启。

RaspberryPi针脚相关的资料,可以参考:http://elinux.org/RPi_Low-level_peripherals

今晚测试了一下,该方法可行。然后就是折腾了整晚的钻孔……还是入手个小电钻吧。期待明天可以接线。

PS。关机按钮的作用是保护SD卡,以免强制断电关机后,发生数据损坏或丢失的情况~

记得刷上Android 4.0之后,想过为什么系统自带了流量监控功能,还要装个监控流量的软件呢?系统自带的流量控制,最大的缺点是不能把流量统计情况显示在桌面上。于是想做个Widget,直接显示系统统计的流量情况。一直拖到上几个星期,终于开工了。但是,面临着一大堆问题……

首先是API。Android统计流量的API都是系统不开放的,就是带了@hilde的类、属性、方法等。

方案1:直接源码编译。首先想到是把android framework的源码下载下来,重新编译成jar包。问题是,CM提供的源码(http://github.com/CyanogenMod/)可能跟Android SDK的对不上。而采用SDK自带的源码,又不能编译。于是直接否决此方案。

方案2:采用Java的反射(Java Reflection)。比编译源码简单多了,什么类都可以拿来用。但是,要写一堆try catch代码,太麻烦了!

方案3:反编译虚拟机上的jar包,即把已编译成dex的jar还原成JVM的jar。由于虚拟机上的jar已被odex化,所以还要先合并。
1)用smali把odex文件转化为dex文件(smali项目:https://code.google.com/p/smali/)。
2)用dex2jar把dex文件转为class文件(dex2jar项目:https://code.google.com/p/dex2jar/)。
3)把class文件打包,并替换SDK上的platforms/android-17/android.jar文件。
这样就可以只用系统的所有api了。但是有个问题,就是system权限的问题未解决。要获得system权限,必须要获得rom的签名。就是说,只能放到rom里面,不能做成通用的软件。

所以,这个项目就研究到这里,然后无限期的暂停了……

在G1时代,入手了蓝牙耳机之后,就一直想把蓝牙耳机当成无线快门来用。虽然很屌丝,但是很实在的一个功能,特别是当年还一个人到处乱逛。

这几天终于启动这个项目。一开始的想法,肯定是参考一些音乐播放软件,利用BroadcastReceiver接受蓝牙耳机的按键事件,再广播一个Camera按键事件,实现从蓝牙的“播放键”到相机的“快门”的动作转换。但是,静态注册了BroadcastReceiver后,不起作用,怀疑是受其它音乐播放软件的影响,但也查不到原因。

后来灵机一动,想起直接修改Android的按键影射文件,把“播放键”直接改成“快门键”。于是修改 /system/usr/keylayout/AVRCP.kl 文件,把 key 200 MEDIA_PLAY WAKE 中的 MEDIA_PLAY 替换成 CAMERA。连上蓝牙后,测试通过,但还有个问题,就是相机不会先自动对焦后拍照,而是直接就拍照。然后就是写个Shell脚本(主要是sed命令吧)来自动修改影射文件。再然后就是写个app来实现这个功能了。当然,这是后话,希望不会成为屁话……

后面还有个想法,通过老G1来自动拍照,上传到服务器,实现监控功能。好吧~继续努力~

今晚,又被阿华拉去“旧车站”喝咖啡,聊聊天。本来跟平常一样的晚上,发生了个小插曲。阿华点了杯冰咖啡,想先喝杯冰水,却被服务员一再拒绝,理由是冰咖啡不送冰水。我望着整个柜子,满满的冰粒,心里纳闷:一杯不怎么值钱的冰水,有那么要紧吗?

记得有个晚上,跟阿华找地方喝点什么,就进了“旧车站”。当时我点了杯柚子蜜茶,阿华的是“意式”。聊着聊着,看到老板在煮单品,于是跟老板聊起了咖啡的事情。不一会,咖啡就煮好了,老板说这是烘培过度的咖啡豆,来自苏门答腊岛,并递给我一杯,让我尝尝。很香,味道浓郁,并从喉咙里散发出一种很甘的感觉,余韵久久不能散去。第一次遇到这么棒的口感!第二天,阿华告诉我,那意式使他一夜难眠,那味道也回味了一夜。从此,我一直在“旧车站”寻找这种单品的味道,阿华也只钟情于那一小杯意式。

从跟老板聊天,到品味那杯苏门答腊,再到一夜的回味,整个过程都很悠闲、随意、舒适!要表达出来的话,就是一种服务,或者氛围,甚至是咖啡馆的文化。很喜欢这种感觉。

类似的事情,在星巴克也遇到过。当时刚推出VIA速溶咖啡,于是买了一包“意识烘培”口味。结帐时, 跟服务员聊起这个新产品。她说,意式的味道比较Strong,要不试下“哥伦比亚”(当时就只有这两个味道)。并送了我一小包“哥伦比亚”。深深感受到星巴克的服务员都很nice。这就不是一个纯粹的买卖,而是在跟客户的简单交流中,让客户感受到一种关怀。当然送个小东西只是一种小手段,重点是能够很好地留住客人。这是我当时很喜欢星巴克的原因,即使咖啡很贵,而且再也没有送VIA给我。

还有一次是到云南大理旅游,在一个专卖咖啡的店,跟老板聊起当地的咖啡豆。聊着聊着,老板就煮了杯当地最好的“金峡谷”让我尝尝。虽然咖啡的味道不是特别喜欢,但是跟老板友好的交谈和看到他非常用心地炮制这杯单品,于是买了点回去。而那杯标价30块的咖啡,老板也没收钱。就像找到知己一样,所作的不是交易,而是一次难忘的偶遇、愉快的经历。

所以,今晚那杯喝不到的冰水伤了一个老顾客的心,也破坏了那种悠闲、随意、舒适的文化。

今天突然发现“二奶”上装的Windows7被错误格式化了,于是想办法重装。折腾了一个晚上,直到11点半,还没搞好。

其实只要用个WinPE启动盘,备份一下C盘的MBR,再用个Ghost装上新系统就完了。但是手上没有WinPE的可启动U盘,也没有能够在Linux上能够使用的制作工具。当然,用过WINE,也用过KVM上运行的WinXP,都不能很好地访问U盘。也折腾过用YUMI制作的启动盘,但不懂其menu的设置,手动添加的iso文件不能启动。最后放弃,只好明天回公司再弄。

洗澡时,不禁在想,其实装个Win7还有没有意义?Lubuntu已经很好地满足我自己的需求了,Chromium、MPlayer、Eclipse、Nginx、PHP等,都能满足日常开发和娱乐的需求。网上支付的话,建行的小额支付,可以用手机验证。至于游戏,WINE能够运行一些经典的游戏,还有手机也能玩一些好玩的。至于那些“大作”,早就没心思去“折腾”了。何不借此机会,把Windows铲除干净?

还是先睡吧~过了明天,就是周末了~

PS.发现近来特健忘,看来有必要开发个任务备忘的手机软件!

首先PHP没有自带定时器(例如每隔几秒自动执行一下某函数)。要实现这个功能,只有三个方法:1)利用外部脚本实现定时执行;2)利用客户端的JavaScript定时执行;3)根据访问请求来实现,但前提是网站的访问量足够大。利用外部脚本实现定时执行,只能是使用虚拟主机或者自己架设服务器才能使用(在虚拟空间上运行,就只能考虑使用JavaScript)。

网上搜到的资料,用PHP页面也可以实现定时器的。主要思路是使用死循环,再加延时执行(即sleep或者usleep函数)。相关示例代码如下:

//------------begin file: timer.php------------
<?php
//每半秒执行记录一下当前时间

//写文件函数
function write_txt() {
    $filePath = 'timer_test.txt';
    if(!file_exists($filePath)){
        $fp = fopen($filePath, 'ab');
        fclose($fp);
    }
    $str = "\r\n" . date('Y-m-d H:i:s');
    $fp = fopen($filePath, 'ab'); //a为打开文件后指向文件末尾,b为以二进制打开文件
    fwrite($fp, $str);
    fclose($fp);
}

ignore_user_abort(); //即使关掉浏览器,PHP也可继续执行
set_time_limit(0); //不设置脚本超时时间,可以无限执行下去
$interval = 30; //时间间隔为30秒
do{
    //定时执行的代码
    write_txt();
    sleep($interval); //等待,sleep的参数单位是秒,usleep的参数单位是毫秒
}while(true); //死循环
//------------end file: timer.php------------

执行时还有个问题,用浏览器打开运行后,网站的其它连接都卡住且不能打开。网上搜到的解析是,PHP不支持多线程。最后只有在服务器上,用以下命令运行:

php timer.php &

终于,在上个星期,匆匆发布了用PHP编写的网站。

其实,与其说是“编写”,还不如说是“搭建”────基于Codeignter框架,采用SQLite,构建而成。基本实现了用户登录、用户管理、简单的笔记管理等。总算实现了N年前,做个PHP网站的计划。

然后考虑了一下Javascript框架采用哪个的问题。Google了一下,主流框架都比较大,例如prototype、jQuery、ExtJs等,根本不适合手机访问,特别是我这种2.5G的网络。于是再找一些轻量级的,例如$dom、zepto、snack等,但都不能完全满足需求。最后,考虑还是自己写一个。很简单,屏蔽各种浏览器的差异,简化一些语句和功能。具体一点,就是统一获取常用数值的函数、$()函数和ajax函数。希望可以尽快开工吧。

由于想把Raspberry Pi改造成无线中继,所以插了两个USB网卡上去。后来发现系统启动后,无线网卡的名称每次都不一定相同,以致启动桥接服务的shell脚本出错。但笔记本上的Lubuntu 12.10却是无线网卡每次的名称都不变。同样是基于Debian,Raspbian也应该可以实现无线网卡名称固定(其实就是跟MAC绑定网络接口名称)。翻查了资料,还是Debian的Wiki比较靠谱。见:http://wiki.debian.org/udev

最后还是比较懒,从Lubuntu 12.10上复制文件 /etc/udev/rules.d/70-persistent-net.rules 到Raspbian上,再改改来用就可以了。该文件修改如下:

## begin the file /etc/udev/rules.d/70-persistent-net.rules #################
# USB Ethernet (usb)
#SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="aa:bb:cc:dd:ee:ff", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="eth*", NAME="eth1"

# USB device 0x0cf3:0x1006 (Mercury MW54U)
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="aa:bb:cc:dd:ee:ff", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="wlan*", NAME="wlan0"

# USB device 0x0bda:0x8171 (Netcore NW338)
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="aa:bb:cc:dd:ee:ff", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="wlan*", NAME="wlan1"
## end the file /etc/udev/rules.d/70-persistent-net.rules #################

其中aa:bb:cc:dd:ee:ff要替换成网卡对应的MAC码。

入手Raspberry Pi Model B (512MB) 已经一段时间了。装上官方的Raspbian,感觉跟手头上的AO522没区别。同样是基于Debian,同样是LXDE桌面。也试了下Xbian (XMBC + Raspbian),感觉非常棒,只是菜单操作有点卡。可惜手上的SD卡空间不够大,否则,还可以玩玩Android。

玩过后,正是按计划进行。首先是作为无线路由来使用。其实就跟Lubuntu共享WiFi一样,测试过程中,还改良了一下以前写的sharewifi脚本(以前的版本:http://www.foxail.org/blog/?p=490)。但是还有一个问题,执行该脚本的stop操作后,系统不会把建立的mon.wlan0接口关闭,需要重启系统,wifi才能从共享模式变成正常的接收模式。

1)sharewifi脚本,设置共享wifi,我放在/opt下,内容如下:(首先要安装hostapd和dnsmasq,执行sudo apt-get install hostapd dnsmasq即可)

### begin the file /opt/sharewifi #########################################
#!/bin/sh

# Setup wireless AP, share the Internet from interface0 to interface1
# USAGE: sharewifi [ start | stop ] interface0 interface1
# EXAMPLE: sharewifi start wlan1 wlan0

help( )
{
    cat << HELP
    Setup wireless AP, share the Internet from interface0 to interface1
    USAGE: sharewifi [ help | start | stop ] interface0 interface1
    EXAMPLE: sharewifi start wlan1 wlan0

    List clients:
    cat /var/lib/misc/dnsmasq.leases
    HELP
    exit 0
}

start( )
{
    echo Starting share wifi ......
    echo Share Internet $port_in to $port_out

    # Configure iptable rules
    iptables -F
    iptables -t nat -A POSTROUTING -s $ip_prefix.0/24 -o $port_in -j MASQUERADE
    iptables -A FORWARD -s $ip_prefix.0/24 -o $port_in -j ACCEPT
    iptables -A FORWARD -d $ip_prefix.0/24 -m conntrack --ctstate ESTABLISHED,RELATED -i $port_in -j ACCEPT

    # Log the message of route
    #iptables -A INPUT -m conntrack --ctstate NEW -p tcp --dport 80 -j LOG --log-prefix "NEW_HTTP_CONN: "

    # Save iptable rules
    sh -c "iptables-save > /etc/iptables.rules"

    # Configure hostapd
    hostapd_conf=/etc/hostapd/hostapd.conf
    [ -f $hostapd_conf ] && rm $hostapd_conf
    echo >> $hostapd_conf interface=$port_out
    echo >> $hostapd_conf driver=nl80211
    echo >> $hostapd_conf ssid=foxrpi-ap
    echo >> $hostapd_conf channel=1
    echo >> $hostapd_conf hw_mode=g
    echo >> $hostapd_conf auth_algs=1
    echo >> $hostapd_conf wpa=3
    echo >> $hostapd_conf wpa_passphrase=1234567890
    echo >> $hostapd_conf wpa_key_mgmt=WPA-PSK
    echo >> $hostapd_conf wpa_pairwise=TKIP CCMP
    echo >> $hostapd_conf rsn_pairwise=CCMP
    chmod 755 $hostapd_conf

    # Configure /etc/dnsmasq.conf
    dnsmasq_conf=/etc/dnsmasq.conf
    [ -f $dnsmasq_conf ] && rm $dnsmasq_conf
    echo >> $dnsmasq_conf interface=$port_out
    echo >> $dnsmasq_conf bind-interfaces #这个是只监听wlan0,没有之会检测所有卡
    echo >> $dnsmasq_conf except-interface=lo
    echo >> $dnsmasq_conf dhcp-range=$ip_prefix.10,$ip_prefix.110,6h #设置dhcp地址范
    chmod 755 $dnsmasq_conf

    # Enable routing
    sysctl net.ipv4.ip_forward=1

    #killall named
    /etc/init.d/hostapd stop
    ifconfig $port_out $ip_prefix.1
    hostapd -B $hostapd_conf
    /etc/init.d/dnsmasq restart

    echo Sucess share wifi

    exit 0
}

stop( )
{
    echo Stopping share wifi ......
    echo Stop share Internet $port_in to $port_out

    # Configure iptable rules
    iptables -F

    # Log the message of route
    #iptables -A INPUT -m conntrack --ctstate NEW -p tcp --dport 80 -j LOG --log-prefix "NEW_HTTP_CONN: "

    # Save iptable rules
    sh -c "iptables-save > /etc/iptables.rules"

    # Configure hostapd
    hostapd_conf=/etc/hostapd/hostapd.conf
    [ -f $hostapd_conf ] && rm $hostapd_conf

    # Configure /etc/dnsmasq.conf
    dnsmasq_conf=/etc/dnsmasq.conf
    [ -f $dnsmasq_conf ] && rm $dnsmasq_conf

    # Enable routing
    sysctl net.ipv4.ip_forward=0

    #killall named
    /etc/init.d/hostapd stop
    /etc/init.d/dnsmasq stop
    ifconfig $port_out down
    ifconfig $port_out del $ip_prefix.1
    ifconfig $port_out up

    echo Sucess stop share wifi

    exit 0
}

ip_prefix=192.168.23 #wifi路由所用网段

#port_in is the network interface which connected to Internet, and default wlan1.
port_in=wlan1

#port_out is the network interface which will be setup AP, and default wlan0.
port_out=wlan0

if [ -n "$2" ]; then
    port_in=$2

    if [ -n "$3" ]; then
        port_out=$3
    fi
fi

case "$1" in
"help" )
    help ;;
"start" )
    start ;;
"stop" )
    stop ;;
*)
    help ;;
esac
### end the file /opt/sharewifi #########################################

2)设置开机自动启动,先编写开机启动的脚本。在/etc/init.d下建立文件sharewifi,文件内容如下:

### begin the file /etc/init.d/sharewifi ######################################### 
#!/bin/sh 
### BEGIN INIT INFO # Provides: sharewifi 
# Required-Start: $syslog 
# Required-Stop: $syslog 
# Default-Start: 2 3 4 5 
# Default-Stop: 0 1 6 
# Short-Description: starts the Wireless AP server 
# Description: starts the Wireless AP using start-stop-daemon 
### END INIT INFO
sharewifi=/opt/sharewifi
NAME=sharewifi
DESC=sharewifi

# Include nginx defaults if available
if [ ! -f $sharewifi ]; then
    echo "Can't find the file $sharewifi"
    exit 1
fi

case "$1" in
start)
    echo -n "Starting $DESC: "
    sh $sharewifi start eth0 wlan0
    echo "$NAME."
    ;;

stop)
    echo -n "Stopping $DESC: "
    sh $sharewifi stop eth0 wlan0
    echo "$NAME."
    ;;

restart)
    echo -n "Restarting $DESC: "
    sh $sharewifi stop eth0 wlan0
    sleep 1
    sh $sharewifi start eth0 wlan0
    echo "$NAME."
    ;;

*)
    echo "Usage: $NAME {start|stop|restart}" >&2
    exit 1
    ;;
esac

exit 0
### end the file /etc/init.d/sharewifi #########################################

3)执行以下命令,即可设置开机启动:

sudo update-rc.d /etc/init.d/sharewifi defaults

终于完成了连续几天的结婚仪式,踏上了去云南的度蜜月旅程。

这半年的准备,真是不堪回首。又或者再回想起跟豆丁的点滴,确实不可思议!人生就是个奇妙的旅程,一切的一切都像是一场梦。梦醒了,都成了过去。

这半年,从买房子开始,两家老人择日子,一个亲戚突然离世,房子装修,拍婚纱照,准备结婚的用品、事情,办结婚证,派喜帖,计划蜜月旅游,接新娘,摆喜酒,中间还考了个小车驾照,最后连满月也提前搞定了。一切都比较顺利,就是缺了个求婚。感觉很匆忙,但又有很多时间。幸好豆丁有办喜事的经验,阿华也比我着急,很多事情都在他们的催促下完成了。

结婚意味着两人的共同生活正式开始了。但由于婚前已跟豆丁一起住了几个月,没感觉什么不适应。

终于在工作4年后完成结婚这个任务,算是从父母的催婚、逼婚压力下解脱了,然后就是生孩子的压力了。唉…