Tuesday, November 19, 2013

PostgreSQL BuildFarm

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.

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:

#!/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.




  • 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
/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


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
$ 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:

  • 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!!

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:

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 :

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);
    }
}