After many years of searching the web for tips and tricks about computers, operating systems and programming languages, it's finally time to give back and post solutions to common problems I'm dealing with.
If your legacy C/C++ code includes <iconv.h> to convert the encoding of characters from one coded character set to another, and you need to cross-compile it with the Android NDK, you will get the following error:
error: iconv.h: No such file or directory
In fact there is currently no iconv.h available in the Android NDK and you will have to port libiconv to Android yourself.
I successfully used the following instructions to cross-compile libiconv.so for Android.
I have Verizon FIOS triple-play service and I love the TV picture quality and internet speed and reliability, but I don't like Verizon's solution to my Parental Control needs. So I've decided to buy an Airport Extreme Base Station (AEBS) from Apple, but when I went to set it up, it configured itself for bridged mode since the Verizon modem is also a router and the Airport Utility decided not to have a double NAT configuration. Anyway by doing so you loose the capability of having a guest network with the Airport Extreme since it dummies itself down from a full fledged router to a simple level-2 switch. So I managed to manually set it up in DHCP/NAT mode even though it is initially complaining about a double NAT configuration (one from the Verizon router and one from the AEBS), but least I gained my guest network back (at the time of this post it is not possible to configure a guest network with the Verizon router).
Hardware Configuration
Apple Router: AirPort Extreme Base Station, Part Number: MD031LL/A
Verizon Modem/Router: Actiontec MI424WR Rev. I
I used a CAT6 Patch cable to connect the AEBS Internet WAN port to Ethernet Port 1 of the Actiontec. This setting allows the two routers to communicate at wire speed of up to 1 GB per second.
Software Configuration
Here is the step by step procedure to set up the Airport Extreme I ran from an iMac running Mountain Lion.
Click on the picture of the Airport Extreme base station: a popup window will show an Edit button
Click on the Edit button
Click on the Network tab and select "DHCP and NAT" from the Router Mode
Click on the Network Options button and select "10.0" for the IPv4 DHCP Range, and "172.16" for the Guest IPv4 DHCP Range. Click on the Save button (see picture below)
Click on the Update button: this will reset the AEBS and cause a solid yellow light with a status of Double NAT. The AEBS will advise you to switch back to bridge mode
Click on the Double NAT Status pull-down menu and select Ignore: after another reboot the AEBS should come up with a solid green color
Regarding the Actiontec configuration, I left it as is, except for disabling the wireless mode to avoid interference with the AEBS.
With an internet browser log on to http://192.168.1.1 using the login and password printed on the bottom of the MI424WR modem/router.
Click on the Wireless Settings icon:
Wireless
Settings
Click on Basic Security Settings from the left panel
Click on Off from the 1. Turn Wireless ON form entry
Click on the Apply button to disable wireless
Considerations
Having the Verizon DHCP server using the 198.168.1.xxx IP addresses range and the AEBS the 10.0.1.xxx range will keep you sane and prevent confusions in your mind about which sub-network you are connected to. In any case these two sub-networks are completely separated and invisible from the Internet and you cannot have a device connected to one subnet talk to another device on the other subnet (unless you start configuring forwarding ports on the AEBS of course). This is OK since I plan to keep all of my computers and devices on the subnet controlled by the AEBS in order to have access control over each device. To my disappointment the Airport Utility version 6.1 used to configure the AEBS is probably one the worst application I ever used to set up a router. It's not intuitive and worst of all it doesn't show who's connected to your network (or at least it doesn't show all the connected devices). In fact it only shows wireless clients in a weird fashion (by hovering over the base station picture), but no sign of any device connected through the Gigabit ethernet ports. By the way the list of wireless client is dynamic and you cannot even copy/paste the MAC addresses to add later to the access control table. I ended up switching to the previous version of Airport Utility (version 5.6 - as suggested by several people on the Internet) since with that you can still get a list of all devices connected to the AEBS from the Advanced->Logs and Statistics->DHCP Clients tab. Still for parental control AEBS only has a time-based table where you can setup a schedule on a per MAC address basis. So I still had to resolve the problem of preventing my kids from hitting questionable web sites. I solved that by setting the OpenDNS servers for primary and secondary DNS servers in my Verizon router. OpenDNS offer a basic parental control filter based on categories. But I found that is is adequate for my needs.
A better solution for cross-compiling Python for Android is to use the Py4A project which is made to be used together with SL4A (Scripting Layer For Android). If you are only interested in the Python interpreter and the runtime Python library, you can also use it standalone.
Get a local copy of the source code using the following command:
Just focus on the python-build subdirectory and make sure the python-build/python-src subdirectory is not present (remove it if it came with the Mercurial repository, or else the compilation will fail).
Set up your environment so that the python-for-android build script can pick up the ndk-build script from the Android NDK:
Finally build Python for Android by issuing the following command:
$ cd python-for-android/python-build
$ rm -rf python-src $ bash build.sh
Note that on my Ubuntu 12.04 machine I had initially the following compilation error:
Traceback (most recent call last): File "build.py", line 161, in <module> os.path.join(pwd, 'output.temp', 'usr')) File "build.py", line 89, in zipup zip_file = zipfile.ZipFile(out_path, 'w', compression=zipfile.ZIP_DEFLATED) File "/home/danilo/python-for-android/python-build/host/lib/python2.6/zipfile.py", line 660, in __init__ "Compression requires the (missing) zlib module" RuntimeError: Compression requires the (missing) zlib module
I identified the problem in having the zlib library in my system installed under /lib/x86_64-linux-gnu/ instead of one of the traditional lib directories covered by the Python setup.py script. Also on my system I only had libz.so.1 and not libz.so. So to fix both problems I just created a symlink in the standard /usr/lib directory as follows:
With this fix the build.sh script was able to successfully build the zlib module for the host environment and create the following zipped files:
python_extras_r14.zip
python-lib_r16.zip
python_r16.zip
python_scripts_r13.zip
Of these I only used the python_r16.zip which contains the stripped python interpreter and the runtime libraries, and the python-lib_r16.zip which contains the include header files such as Python.h that can be used to compile Python bindings at development time.
I have posted on YouTube a couple of videos about a project I made
with the Arduino prototype board. The circuit uses an Arduino mini and
has a simple gear counter based on a 7-segment LED and controlled by two
switches. It can be mounted on your bike and used for example to
visualize which gear you are in at any time.
If you are interested in the schematics I have the PCB Artist version downloadable here:
/*
Blink
Turns on an LED on for one second, then off for one second, repeatedly.
The circuit:
* LED connected from digital pin 13 to ground.
* Note: On most Arduino boards, there is already an LED on the board
connected to pin 13, so you don't need any extra components for this example.
Created 1 June 2005
By David Cuartielles
http://arduino.cc/en/Tutorial/Blink
based on an orginal by H. Barragan for the Wiring i/o board
*/
#define BUTTON_DOWN 10
#define BUTTON_UP 12
int ledPinA = 6; // LED connected to digital pin 3
int ledPinB = 9; // LED connected to digital pin 4
int ledPinC = 4; // LED connected to digital pin 5
int ledPinD = 3; // LED connected to digital pin 6
int ledPinE = 2; // LED connected to digital pin 7
int ledPinF = 7; // LED connected to digital pin 8
int ledPinG = 8; // LED connected to digital pin 9
int ledPinDP = 5; // LED connected to digital pin 10
int val_down = 0;
int old_val_down = 0;
int val_up = 0;
int old_val_up = 0;
int state = 0;
int gear = 1;
// The setup() method runs once, when the sketch starts
void setup() {
pinMode(BUTTON_DOWN, INPUT);
pinMode(BUTTON_UP, INPUT);
// initialize the digital pin as an output:
pinMode(ledPinA, OUTPUT);
pinMode(ledPinB, OUTPUT);
pinMode(ledPinC, OUTPUT);
pinMode(ledPinD, OUTPUT);
pinMode(ledPinE, OUTPUT);
pinMode(ledPinF, OUTPUT);
pinMode(ledPinG, OUTPUT);
pinMode(ledPinDP, OUTPUT);
// initialize serial communication:
Serial.begin(9600);
}
void led0()
{
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinE, LOW);
digitalWrite(ledPinF, LOW);
digitalWrite(ledPinG, HIGH);
digitalWrite(ledPinDP, HIGH);
}
void led1()
{
digitalWrite(ledPinA, HIGH);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, HIGH);
digitalWrite(ledPinE, HIGH);
digitalWrite(ledPinF, HIGH);
digitalWrite(ledPinG, HIGH);
digitalWrite(ledPinDP, HIGH);
}
void led2()
{
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, HIGH);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinE, LOW);
digitalWrite(ledPinF, HIGH);
digitalWrite(ledPinG, LOW);
digitalWrite(ledPinDP, HIGH);
}
void led3()
{
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinE, HIGH);
digitalWrite(ledPinF, HIGH);
digitalWrite(ledPinG, LOW);
digitalWrite(ledPinDP, HIGH);
}
void led4()
{
digitalWrite(ledPinA, HIGH);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, HIGH);
digitalWrite(ledPinE, HIGH);
digitalWrite(ledPinF, LOW);
digitalWrite(ledPinG, LOW);
digitalWrite(ledPinDP, HIGH);
}
void led5()
{
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, HIGH);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinE, HIGH);
digitalWrite(ledPinF, LOW);
digitalWrite(ledPinG, LOW);
digitalWrite(ledPinDP, HIGH);
}
void led6()
{
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, HIGH);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinE, LOW);
digitalWrite(ledPinF, LOW);
digitalWrite(ledPinG, LOW);
digitalWrite(ledPinDP, HIGH);
}
void led7()
{
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, HIGH);
digitalWrite(ledPinE, HIGH);
digitalWrite(ledPinF, HIGH);
digitalWrite(ledPinG, HIGH);
digitalWrite(ledPinDP, HIGH);
}
void led8()
{
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinE, LOW);
digitalWrite(ledPinF, LOW);
digitalWrite(ledPinG, LOW);
digitalWrite(ledPinDP, HIGH);
}
void led9()
{
digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinE, HIGH);
digitalWrite(ledPinF, LOW);
digitalWrite(ledPinG, LOW);
digitalWrite(ledPinDP, HIGH);
}
void ledDP()
{
digitalWrite(ledPinA, HIGH);
digitalWrite(ledPinB, HIGH);
digitalWrite(ledPinC, HIGH);
digitalWrite(ledPinD, HIGH);
digitalWrite(ledPinE, HIGH);
digitalWrite(ledPinF, HIGH);
digitalWrite(ledPinG, HIGH);
digitalWrite(ledPinDP, LOW);
}
void setLed(int number)
{
switch (number) {
case 0:
ledDP();
break;
case 1:
led1();
break;
case 2:
led2();
break;
case 3:
led3();
break;
case 4:
led4();
break;
case 5:
led5();
break;
case 6:
led6();
break;
case 7:
led7();
break;
case 8:
led8();
break;
case 9:
led9();
break;
}
}
// the loop() method runs over and over again,
// as long as the Arduino has power
void oldloop()
{
ledDP();
delay(1000); // wait for a second
led0();
delay(1000); // wait for a second
led1();
delay(1000); // wait for a second
led2();
delay(1000); // wait for a second
led3();
delay(1000); // wait for a second
led4();
delay(1000); // wait for a second
led5();
delay(1000); // wait for a second
led6();
delay(1000); // wait for a second
led7();
delay(1000); // wait for a second
led8();
delay(1000); // wait for a second
led9();
delay(1000); // wait for a second
}
void loop()
{
val_up = digitalRead(BUTTON_UP);
if ((val_up == HIGH) && (old_val_up == LOW)) {
gear += 1;
Serial.print("gear number: ");
Serial.println(gear, DEC);
delay(100);
}
old_val_up = val_up;
val_down = digitalRead(BUTTON_DOWN);
if ((val_down == HIGH) && (old_val_down == LOW)) {
gear -= 1;
Serial.print("gear number: ");
Serial.println(gear, DEC);
delay(100);
}
old_val_down = val_down;
if (gear >= 6) {
gear = 6;
}
if (gear <= 1) {
gear = 1;
}
setLed(gear);
}
When it comes to cross-compiling Python for Android, I've followed Gabriel's blog post @ http://mdqinc.com/blog/2011/09/cross-compiling-python-for-android/ and I was successful in creating an Arm-based Python executable (and related libraries) in little or no time.
Gabriel has a lot of the initial steps just verbally described, but I've come up with a shell script that allows you to automate the entire process. Of course you need to replace <path-to-android-ndk> with the directory where you have installed the NDK.
Here it goes.
output_dir=$1 mkdir -p $output_dir cd $output_dir # get Python source tarball wget http://www.python.org/ftp/python/$PYTHON_VERSION/Python-$PYTHON_VERSION.tgz
# create Python Host version tar zxvf Python-$PYTHON_VERSION.tgz mv Python-$PYTHON_VERSION Host-Python-$PYTHON_VERSION-src cd Host-Python-$PYTHON_VERSION-src ./configure --prefix=$output_dir/Host-Python-$PYTHON_VERSION make make install
cd $output_dir # create Python Cross-compiled version for Android tar zxvf Python-$PYTHON_VERSION.tgz mv Python-$PYTHON_VERSION Android-Python-$PYTHON_VERSION-src cd Android-Python-$PYTHON_VERSION-src
Suppose you have a single tar ball and you want to create two or more RPMs using different spec files. The new version of rpmbuild automatically cleans the BUILDROOT directory after completing the targets for a given spec file. If you want to save time and have the second spec file just look for the BUILDROOT created by the first spec it won't find it because of the automatic clean. So it seems like you are forced to untar and install under the BUILDROOT your file over and over again.
A simple solution to this problem is to add a %clean directive to your spec file and do nothing to disable to automatic cleaning done by rpmbuild. Add the following line at the bottom of your spec file:
This is a recurring problem people have often: trying to port a big C/C++ project to the Android platform. You have thousands of lines of tested and working C/C++ code that you want to reuse and access from your Android application. So far Android only provides an SDK for Java applications, only supports devices with ARM, MIPS and x86 architectures, and several steps are necessary if you want to port your code and call it from Java as a library. By large the biggest deployment is for ARM processor devices, so we are initially focused on porting our code to this architecture.
Porting your C/C++ project to the Android platform entails then the following steps:
Cross-compile the C/C++ code for the ARM processor (or any other supported) architecture.
Develop a JNI module allowing an Android application to natively call the C/C++ code from Java.
Develop an Android application using the JNI module.
Run and debug the app on an Android device.
Developing an Android application requires the Android Software Development Kit (SDK), while cross-compiling your C/C++ code and developing the JNI module for Android requires the Android Native Development Kit (NDK). Both these kits run on Windows XP/Win7, Mac OS 10.5.8 or later (Intel), or Ubuntu Linux 8.04 or later.
My intention is to publish on this blog several posts with detailed instructions on how to accomplish the above mentioned steps. The instructions are based on other posts you can search on the internet and on my experience with Android. All the instructions are based on the development and testing environments described below.
Development Environment
Processor: Intel(R) Core(TM) 2 Duo CPU E8600 @ 3.33GHz
Android devices have file systems similar to regular computers. Subject to permissions restrictions, we can transfer files from a computer to a device (connected to the computer by USB) or emulator, or from the device or emulator to the computer. There are several ways to transfer files to an Android device:
Using Eclipse
Select the DDMS perspective for Eclipse and use the File Explorer tab to select the directory where you want to tranfer a file to (a drawback of using this method is that you can only tranfer one file at a time).
Using the ADB
You can tranfer entire directories using the ADB command line interface. For example to transfer the entire content of a director to an Android device connected to a Ubuntu computer via the USB port:
$ adb push <path to directory to copy> /mnt/sdcard/<target directory>
Install an ssh daemon on the Android device and then use sftp from your workstation. For example you can download the free SSHDroid app from the Google market and install it on your device, run the app an find out about the IP address to connect to. Then from a terminal window in Linux you can connect like this (works on Ubuntu 12.04):
After many years of searching the web for tips and tricks about computers, operating systems and programming languages, it's finally time to give back and post solutions to common problems I'm facing during my professional career.