One of my BeagleBone Black boards is currently running two PostgreSQL BuildFarm instances: one with gcc and one with clang.
A great way to show your support to open source software.
Tuesday, November 19, 2013
Saturday, September 14, 2013
Using the Power Button on Beaglebone Black for Shutdown
By default, when pressing the Power button on Beaglebone Black (BBB) for 8 seconds, the board will be powered off. However, this is not properly shutting down the OS.
Instead, I would like to use the power button to issue the shutdown command. After some research, found that the power button generates events that can be captured by monitoring /dev/input/event0.
Here is the script:
The script reads the first 16 bytes and see if it contains 0x74, which is the code for power button. If so, it will execute the shutdown command. Otherwise, sleep for awhile and monitor again.
The script is add to /etc/rc.local in order to be executed after every reboot
Instead, I would like to use the power button to issue the shutdown command. After some research, found that the power button generates events that can be captured by monitoring /dev/input/event0.
Here is the script:
#!/bin/sh
BTN=/dev/input/event0
while true; do
BTNVAL=`hexdump -e '8/2 "%x " "n"' -n 16 $BTN | grep ' 74 ' | awk '{print $7}'`
if [ "$BTNVAL" = "1" ]
then
echo "Power button pressed"
/bin/sync; /bin/sync; /sbin/shutdown -h now
exit 0
fi
sleep 1
done
The script reads the first 16 bytes and see if it contains 0x74, which is the code for power button. If so, it will execute the shutdown command. Otherwise, sleep for awhile and monitor again.
The script is add to /etc/rc.local in order to be executed after every reboot
/root/scripts/pwrbtncheck.sh > /dev/null 2>&1 &
Wednesday, September 4, 2013
DIY Constant Current Charger for AA / AAA NiMH Battery
Normally I use my MH-C9000 to recharge and condition my AA / AAA batteries. However, it wont charge some of my older batch batteries. Maybe the internal resistance is just too high.
Even with low capacity, these old batteries are good for mouse etc low power devices. So instead of throwing them away, they are charged with a slow constant current charger. Here is a simple design of such charger.
Pros:
Cons:
Even with low capacity, these old batteries are good for mouse etc low power devices. So instead of throwing them away, they are charged with a slow constant current charger. Here is a simple design of such charger.
- The design is powered by +5v. I usually use a phone charger or a computer USB port
- The yellow LED has a +2v drop. With a 0.7v Base-Emitter voltage of BC337, that means there is 1.3v across R2
- With R2 = 12 ohm, the charging current is around 1.3v / 12 ohm = 0.108A
- With a 1000mAh battery, the charging rate is around 0.1C. Good for slow charging
Pros:
- Simple to make. I just used components I found in my DIY junk box. Resistors and transistors can be replaced by other parts. Just make sure you calculate the charging current correctly
Cons:
- No terminate logic. Batteries will be charged until removed. Make sure you don't overcharge your batteries
When the +5v power source is removed, the battery will be powering the LED. Adding a diode could solve the issue. But to keep it simple, I left that out and simply remove the batteries after charging
Thursday, June 13, 2013
Beaglebone Black, ANT+, and Garmin FR70
My BBB is running Debian. Your mileage may vary if your BBB is running the stock Ångström.
Just successfully extracted data from my Garmin FR70 to BBB via a Garmin ANT+ USB stick. The steps are quite simple once you figured what software you need.
Note that different version of Garmin products use different protocol to communicate. The program Garmin-Forerunner-610-Extractor supports the followings:
- Garmin Forerunner 60 - Garmin Forerunner 405CX - Garmin Forerunner 310XT - Garmin Forerunner 610 - Garmin Forerunner 910XT - Garmin FR70 - Garmin Swim
Basically you just follow the instructions on the page. To sync with your BBB the first time, remember to turn on the Pairing function on you device. On my FR70, it is under Settings > System > Computer > Pairing.
For other devices
If you are using other devices that are not supported by Garmin-Forerunner-610-Extractor, go check out garmin-ant-downloader (this can be installed via apt-get). If you are using garmin-ant-downloader, your may need to create the USB serial device manually on your BBB. After you plugged in the ANT+ USB stick, use the lsusb command to list the device:
debian@debian-armhf:~/garmin$ lsusb Bus 001 Device 002: ID 058f:6254 Alcor Micro Corp. USB Hub Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 001 Device 003: ID 154b:0062 PNY Bus 001 Device 008: ID 0fcf:1008 Dynastream Innovations, Inc.
The last device is my ANT+ stick. The garmin-ant-downloader needs to access the stick via a serial device. By default, it is the /dev/ttyUSB0. If it is not created automatically, use the following command:
sudo modprobe usbserial vendor=0x0fcf product=0x1008
Where 0x0fcf and 0x1008 are the code from the lsusb command result. Use the values that correspond to the output of your stick.
Using Oracle JDK 8 for ARM Early Access VM in OpenJDK under BeagleBoneBlack
Note that Oracle 8 JDK official release for ARM is out. There is no need to follow the steps below. Also, if you want to install it via apt-get, you may refer to this link.
Following similar instructions for Raspberry Pi, here are the instructions on how to boost the Java performance on BeagleBone Black by using Oracle's JDK 8 Early Access HotSpot with OpenJDK.
Note that I am using Debian on my BBB
Install openjdk
Optional. Download a benchmark program. Save it as fastaredux.java and test the performance of the stock OpenJDK.
Download the JDK 8 for ARM Early Access package from Oracle web site.
Following the instructions, extract the hotspot VM and add it to OpenJDK
Make the HotSpot VM as our default VM. Edit the file /etc/java-7-openjdk/jvm-armhf.cfg and add -oracle KNOWN as the first parameter. (or, as stated in the instructions, use the sed command to add it to the first line of the file)
Note the last line of the output. Now it changed to use HotSpot VM
Result of running the same benchmark. The performance almost tripled.
Note that using the -server option on the HotSpot VM seems to slow down the performance though.
Using the -server option will actually switch back to use the default OpenJDK Zero VM
You can also alias -server option to use HotSpot VM:
PS. Here is the before vs after result on my Raspberry Pi.
Before:
After:
Following similar instructions for Raspberry Pi, here are the instructions on how to boost the Java performance on BeagleBone Black by using Oracle's JDK 8 Early Access HotSpot with OpenJDK.
Note that I am using Debian on my BBB
Install openjdk
/mnt/usb/debian/test$ sudo apt-get install openjdk-7-jdk
Optional. Download a benchmark program. Save it as fastaredux.java and test the performance of the stock OpenJDK.
/mnt/usb/debian/test$ java -version java version "1.7.0_03" OpenJDK Runtime Environment (IcedTea7 2.1.7) (7u3-2.1.7-1) OpenJDK Zero VM (build 22.0-b10, mixed mode) /mnt/usb/debian/test$ javac fastaredux.java /mnt/usb/debian/test$ time java -XX:+TieredCompilation -XX:+AggressiveOpts fastaredux 25000000 > /dev/null 2>&1 real 1m40.294s user 1m40.047s sys 0m0.180s
Download the JDK 8 for ARM Early Access package from Oracle web site.
Following the instructions, extract the hotspot VM and add it to OpenJDK
/mnt/usb/debian/test$ tar --extract --verbose --file=jdk-8-ea-b36e-linux-arm-hflt-29_nov_2012.tar.gz jdk1.8.0/jre/lib/arm/client jdk1.8.0/jre/lib/arm/client/ jdk1.8.0/jre/lib/arm/client/Xusage.txt jdk1.8.0/jre/lib/arm/client/libjvm.so jdk1.8.0/jre/lib/arm/client/libjsig.so /mnt/usb/debian/test$ sudo mv jdk1.8.0/jre/lib/arm/client /usr/lib/jvm/java-7-openjdk-armhf/jre/lib/arm/oracle /mnt/usb/debian/test$ sudo chown -R root:root /usr/lib/jvm/java-7-openjdk-armhf/jre/lib/arm/oracle
Make the HotSpot VM as our default VM. Edit the file /etc/java-7-openjdk/jvm-armhf.cfg and add -oracle KNOWN as the first parameter. (or, as stated in the instructions, use the sed command to add it to the first line of the file)
-oracle KNOWN -server KNOWN -client IGNORE -hotspot ERROR -classic WARN -native ERROR -green ERROR -zero ALIASED_TO -server -cacao KNOWN -zero ERROR -shark ERROR -jamvm KNOWN
Note the last line of the output. Now it changed to use HotSpot VM
/mnt/usb/debian/test$ java -version java version "1.7.0_03" OpenJDK Runtime Environment (IcedTea7 2.1.7) (7u3-2.1.7-1) Java HotSpot(TM) Client VM (build 25.0-b04, mixed mode)
Result of running the same benchmark. The performance almost tripled.
/mnt/usb/debian/test$ time java -XX:+TieredCompilation -XX:+AggressiveOpts fastaredux 25000000 > /dev/null 2>&1 real 0m35.102s user 0m34.906s sys 0m0.166s
Using the -server option will actually switch back to use the default OpenJDK Zero VM
$ java -server -version java version "1.7.0_03" OpenJDK Runtime Environment (IcedTea7 2.1.7) (7u3-2.1.7-1) OpenJDK Zero VM (build 22.0-b10, mixed mode) $ java -version java version "1.7.0_03" OpenJDK Runtime Environment (IcedTea7 2.1.7) (7u3-2.1.7-1) Java HotSpot(TM) Client VM (build 25.0-b04, mixed mode)
You can also alias -server option to use HotSpot VM:
-oracle KNOWN -server ALIASED_TO -oracle #-server KNOWN -client IGNORE -hotspot ERROR -classic WARN -native ERROR -green ERROR -zero ALIASED_TO -server -cacao ERROR -zero ERROR -shark ERROR -jamvm KNOWN
PS. Here is the before vs after result on my Raspberry Pi.
Before:
pi@raspberrypi ~/test $ time java -XX:+TieredCompilation -XX:+AggressiveOpts fastaredux 25000000 > /dev/null 2>&1 real 8m4.807s user 7m56.410s sys 0m1.880s
After:
pi@raspberrypi ~/test $ time java -XX:+TieredCompilation -XX:+AggressiveOpts fastaredux 25000000 > /dev/null 2>&1 real 0m44.109s user 0m43.160s sys 0m0.320s
Wednesday, June 12, 2013
OpenCV facial recognition with BeagleBone Black
After flashing my BBB with Debian, I proceed to install OpenCV and the required Python packages. Using the sample code from here, I could get the facial and eye recognition demo running in a few minutes!
A few points to note:
A few points to note:
- I am running Debian Wheezy on my BBB with the image flashed to eMMC. It is a headless setup. Connect to it from my Windows PC using putty and Xming
- BBB seems to be having problem when the webcam resolution is too high. The sample code ran OK when the witdth and height set as 320x240 or 352x288
- For the facial recognition sample, some external XML files are required. You may get them from the OpenCV source code package. Just modify the sample code to point to the correct directory
Monday, June 10, 2013
Ångström...
I think I will give up Ångström and flash Debian Wheezy onto the eMMC of my BeagleBond Black directly...
Sunday, June 9, 2013
Upgrading Ångström on Beaglebone Black
Got my BBB a few weeks ago. My first attempt to update and upgrade the stock Ångström failed. I knew that the in memory /tmp is not big enough for "opkg upgrade" to store the downloaded packages. So I added the "-t" switch to write the temp files to another directory.
However, even the BBB eMMC is not big enough. The upgrade failed and probably corrupted the base. Needed to re-flash the eMMC.
Notes to self: Plug in a USB stick and use it as temp storage for "opkg upgrade" next time!!
However, even the BBB eMMC is not big enough. The upgrade failed and probably corrupted the base. Needed to re-flash the eMMC.
Notes to self: Plug in a USB stick and use it as temp storage for "opkg upgrade" next time!!
Friday, October 12, 2012
Testing Raspberry Pi network speed
Just got another Rapsberry Pi board. This time a 2.0 board (made in the UK!!). Anyway, doing a network (or USB, since the ethernet is via USB) stress test with the following command:
That caused 100% CPU loading on the Raspberry Pi. Throughput is about 6MB per second.
cat /dev/zero | ssh username@remotehost "cat > /dev/null"
That caused 100% CPU loading on the Raspberry Pi. Throughput is about 6MB per second.
Monday, October 1, 2012
Using PMD to scan explicit/implicit casting of BigDecimal to String
At work, a project needed to be upgraded from Java 1.4 to Java 1.6. One of the big issues introduce in Java 1.5 was the behavior change of the toString method of BigDecimal. Under certain situation, it now returns the string in using scientific notation. This change was based on JSR 13. While the change is justifiable, some question if the expert group underestimated the behavioral compatibility impact, especially with programs that interface with databases.
Anyway, one way (the way we used at work) to solve the issue is to use the new method toPlainString. We grep the code to find all the toString method calls and manually change them to toPlainString. But not only this is prone to error, there are many cases that can't be detected. For example, this code doesn't call the toString method explicitly but still affected by the compatibility issue :
There ought to be a better (and automated) way to scan the source tree. So during a long weekend, I spent a day to play with PMD. Below is a rule that I implemented to do the job. Part of it is based on a sample found in the PMD package.But note that this still CANNOT find all the cases of BigDecimal.toString (more about that later).
Here is the ruleset file:
Command to test the rule:
Below is a sample test case. As said, there are cases that cannot be detected by my PMD rule. For example, concatenating a string with a BigDecimal return value from method call. Or, passing a BigDecimal to a method that takes an Object parameter and internally invoking the toString method.
Anyway, feel free to take the code and make it better~!
Anyway, one way (the way we used at work) to solve the issue is to use the new method toPlainString. We grep the code to find all the toString method calls and manually change them to toPlainString. But not only this is prone to error, there are many cases that can't be detected. For example, this code doesn't call the toString method explicitly but still affected by the compatibility issue :
String s = "" + bd;
There ought to be a better (and automated) way to scan the source tree. So during a long weekend, I spent a day to play with PMD. Below is a rule that I implemented to do the job. Part of it is based on a sample found in the PMD package.But note that this still CANNOT find all the cases of BigDecimal.toString (more about that later).
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.List;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter;
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;
import net.sourceforge.pmd.lang.java.ast.ASTType;
import net.sourceforge.pmd.lang.java.ast.ASTLiteral;
import net.sourceforge.pmd.lang.java.ast.ASTName;
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
import net.sourceforge.pmd.lang.java.ast.ASTAdditiveExpression;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
import net.sourceforge.pmd.lang.java.symboltable.NameOccurrence;
import net.sourceforge.pmd.util.CollectionUtil;
/**
*
*/
public class ScanBigDecimal extends AbstractJavaRule {
/**
* These are the BigDecimal methods
*/
private static final Set<String> BIG_DECIMAL_METHODS = CollectionUtil.asSet(new String[] { ".toString" });
/**
* These are the classes that the rule can apply to
*/
private static final Map<String, Set<String>> MAP_CLASSES = new HashMap<String, Set<String>>();
static {
MAP_CLASSES.put("java.math.BigDecimal", BIG_DECIMAL_METHODS);
MAP_CLASSES.put("BigDecimal", BIG_DECIMAL_METHODS);
}
@Override
public Object visit(ASTLocalVariableDeclaration node, Object data) {
ASTVariableDeclaratorId var = getDeclaration(node);
if (var == null) {
return super.visit(node, data);
}
String variableName = var.getImage();
for (NameOccurrence no: var.getUsages()) {
// FIXME - getUsages will return everything with the same name as the variable,
// see JUnit test, case 6. Changing to Node below, revisit when getUsages is fixed
Node sn = no.getLocation();
Node primaryExpression = sn.jjtGetParent().jjtGetParent();
Class<? extends Node> parentClass = primaryExpression.jjtGetParent().getClass();
// see if we are calling the methods we are interested in
String methodCall = sn.getImage().substring(variableName.length());
ASTType nodeType = node.getTypeNode();
if (nodeType != null && MAP_CLASSES.get(nodeType.getTypeImage()).contains(methodCall)) {
addViolation(data, sn);
}
}
return super.visit(node, data);
}
@Override
public Object visit(ASTAdditiveExpression node, Object data) {
boolean hasLiteral = true;
boolean hasClass = false;
if (node == null) {
return super.visit(node, data);
}
for (int i = 0; i < node.jjtGetNumChildren(); i++) {
Node child = node.jjtGetChild(i);
if (child.hasDescendantOfType(ASTLiteral.class)) {
hasLiteral = true;
} else {
ASTName nameNode = (ASTName)child.getFirstDescendantOfType(ASTName.class);
if (nameNode != null && findDeclaration(node, nameNode.getImage()) != null) {
hasClass = true;
}
}
if (hasLiteral && hasClass) {
addViolation(data, node);
break;
}
}
return super.visit(node, data);
}
/**
* This method checks the variable declaration if it is on a class we care
* about. If it is, it returns the DeclaratorId
*
* @param node
* The ASTLocalVariableDeclaration which is a problem
* @return ASTVariableDeclaratorId
*/
private ASTVariableDeclaratorId getDeclaration(ASTLocalVariableDeclaration node) {
ASTType type = node.getTypeNode();
if (MAP_CLASSES.keySet().contains(type.getTypeImage())) {
return node.getFirstDescendantOfType(ASTVariableDeclaratorId.class);
}
return null;
}
private ASTVariableDeclaratorId findDeclaration(Node node, String varName) {
if (node == null || varName == null) {
return null;
}
Node parent = node.getFirstParentOfType(ASTClassOrInterfaceBodyDeclaration.class);
if (parent != null) {
List<ASTVariableDeclaratorId> list = parent.findDescendantsOfType(ASTVariableDeclaratorId.class);
for (ASTVariableDeclaratorId declarator : list) {
if (varName.equals(declarator.getImage())) {
ASTType nodeType = null;
if (declarator.jjtGetParent() instanceof ASTFormalParameter) {
nodeType = ((ASTFormalParameter)(declarator.jjtGetParent())).getTypeNode();
} else if (declarator.jjtGetParent() instanceof ASTLocalVariableDeclaration) {
nodeType = ((ASTLocalVariableDeclaration)(declarator.jjtGetParent())).getTypeNode();
} else if (declarator.jjtGetParent() instanceof ASTVariableDeclarator) {
nodeType = ((ASTLocalVariableDeclaration)(declarator.jjtGetParent().jjtGetParent())).getTypeNode();
} else {
System.err.println("Unknown type");
}
if (nodeType != null && MAP_CLASSES.keySet().contains(nodeType.getTypeImage())) {
return declarator;
}
}
}
}
return null;
}
}
Here is the ruleset file:
<?xml version="1.0"?>
<ruleset name="My custom rules"
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd"
xsi:noNamespaceSchemaLocation="http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
<rule name="ScanBigDecimal"
message="Avoid using BigDecimal.toString or implicit casting to string"
class="ScanBigDecimal">
<description>
Avoid using BigDecimal.toString or implicit casting to string
</description>
<priority>3</priority>
<example>
<![CDATA[
}
]]>
</example>
</rule>
</ruleset>
Command to test the rule:
java -cp "C:/Users/clarence/Documents/MyApps/pmd-bin-5.0.0/lib/*";. net.sourceforge.pmd.PMD C:/Users/clarence/Documents/MyTest/pmd/MyTestCase.java text bigdecimal.xml
Below is a sample test case. As said, there are cases that cannot be detected by my PMD rule. For example, concatenating a string with a BigDecimal return value from method call. Or, passing a BigDecimal to a method that takes an Object parameter and internally invoking the toString method.
Anyway, feel free to take the code and make it better~!
import java.math.BigDecimal;
public class MyTestCase {
public static void main(String args) {
BigDecimal bd = new BigDecimal("12.345");
// will trigger error
System.out.println("This is the number: " + bd);
// this type can't be detected...
System.out.println(bd);
// will trigger error;
String s = "" + bd;
String s2 = "" + bd.toString();
String s3 = bd + "";
String s4 = bd + MyTestCase.returnStr();
// can't be detected
String s5 = "" + returnBigDecimal("12.34");
System.err.println(returnString(bd));
// this wont trigger warning
String s6 = "" + bd.toPlainString();
String s7 = "" + "a" + "b";
}
private static String returnStr() {
return "hello";
}
private static String returnString(BigDecimal bd) {
return "" + bd;
}
private static BigDecimal returnBigDecimal(String num) {
return new BigDecimal(num);
}
}
Subscribe to:
Posts (Atom)




