Skip to content


C++ Idiom: Copy-and-Swap

Adapted from this stackoverflow article

Copy-and-swap idiom is a elegant solution that performs assignment while avoiding code duplication and strong exception guarantee. Conceptually, it utilizes the object’s copy-constructor to create a local copy of itself, performs assignment to the other object through a swap method and then destroys the other object’s old data when the swapped local copy’s destructor.

Through the rule of three, the highlighted components (in bold) should all be present anyway except the swap method. The swap method must be non-throwing function. Notice that std::swap does not qualify as it uses the copy-constructor and assignment operator in its implementation (and we are trying to implement the assignment operator).

From this point, see the stackoverflow article for an example

Posted in C/C++, idioms. Tagged with , .

C++ Idiom: Rule of Three

The rule of three idiom says that if a class needs any of:

  • copy constructor
  • assignment operator
  • destructor

Then it probably need all of them.

The reason for this is that if any of the above is needed then the class likely manages its own resource (allocation/deletion) and this is likely to be needed for all of the actions.

Posted in C/C++, idioms. Tagged with , , , , , .

C/C++ – Casting int pointer to char pointer

There was some interesting discussion around the following code, and I thought I would write it up here.

// Part I:
int    i = 0x01234567;
int*  pi = &i;
char* pc = pi;

// Part II:
char  c = 0x80;
int* pi = &c;

Now, code in Part I is fine, while code in Part II has a problem. The C standard (C99) maintains that:

  • ints are 4-byte aligned
  • chars are 1-byte aligned
  • data memory are byte addressable
  • casting misaligned pointer types results in undefined operation

This means that a char* can address any data (such as an int) while the reverse may not be true. In the particular case above this means that while any int* can be converted to a char* (and back again), a random char* may not be convertible to an int*.

Even though an int* can be casted into a char*, notice that for big/little-endians, the byte orders are different so care should be taken when using this type of cast.

Now, for a little more depth, why is it that an arbitrary char* cannot be converted into an int*?
Most current CPUs are byte-addressable, meaning that each memory address points to an 8-bit block of memory cells. Many CPU instructions that operate on data stored in memory allow the data to have a size larger than 1 byte and would attempt to access the memory to read up to the size of the data type (e.g. 8 byte floating point operations). Data are naturally aligned if the starting address can be expressed as multiples of power of 2. For example 0x8 is aligned to 2,4… (See here for a full definition)

Some CPUs (x86 for example) can read misaligned data by performing multiple memory accesses and piecing together the data (for example half of the float from 1 access and the other half from another). Many CPUs however (such as MIPS, IA-64 etc) will not read data that are misaligned and any attempt raises a bus error (SIGBUS on POSIX), so if you cast a char* to int* and the start address of the new int* is not aligned, then any 4-byte aligned access to that location fails with bus error.

Posted in C/C++, MSP430. Tagged with , , , .

Fully statically linked Perl – Single executable with all modules, modules fully statically linked also (bundle Crypt::OpenSSL::AES)

Recently I had to figure out how to distribute a single Perl that includes Crypt::OpenSSL::AES module that works across multiple Linux distributions and architectures. There are several problems:

  • Perl has dependencies on shared libraries that may not exist on all systems. This is not by itself a huge problem because you can build a single 32 Bit Perl that work on major distributions
  • Crypt::OpenSSL::AES is a thin wrapper for libcrypto and libssl. This means that when you install the module, it is compiled as a shared library. This is a significant problem because OpenSSL is not backward compatible, so you need all of your target machine to have the same version of libcrypto and libssl and built for the same architecture and using same or better version of libc (and other shared libraries). To see the dependencies, use ldd

Statically linking the shared library built during installation of Crypt::OpenSSL::AES against libcrypto does solve the 2nd part of the problem but not the first. It also means that you are still bounded by the libc version requirements.

After much research, I have found a way to build a fully static (alternatively static perl with dependency only on libc). The method uses App-Staticperl (http://search.cpan.org/~mlehmann/App-Staticperl-1.43/bin/staticperl). Reader should familiarize themselves with the documentation in the link first.


Installation:

  1. Download and Build OpenSSL, the build require no special configuration parameters. If you need to build OpenSSL in a local directory refer to OpenSSL’s INSTALL file for the configuration flags
  2. Patch App-Staticperl. The standard download does not work out of the box due to a script error.
    • Untar App-Staticperl
    • Copy the staticperl.sh into the untarred directory
  3. Build perl from source using staticperl by running ‘./staticperl.sh install’, this installs by default Perl 5.12.4 to ~/.staticperl
  4. Copy ./mkbundle to ~/.staticperl/bin/SP-mkbundle. This step is required to work around a script error in staticperl.sh that prevents it from generating the mkbundle script
  5. Run ./staticperl.sh mkperl, if there are any missing module errors then install the corresponding module from CPAN using ~/.staticperl/bin/perl
  6. Build and install CBC::Crypt:
    • Untar Crypt-CBC
    • CD into the new directory and issue:
    • ~/.staticperl/bin/perl Makefile.PL
      make
      make install
  7. Build and install Crypt::OpenSSL::AES. This require modification to Makefile.PL to statically link in the OpenSSL library built during step 1
    • Untar Crypt::OpenSSL::AES
    • CD into the new directory and modify the Makefile.PL
    • Comment out LIBS
      Add path to the build openssl's include dir to INC
      Add MYEXTLIB => 'POINT TO libcrypto.a FILE' # this gets directly added to the linker
    • Issue commands:
    • ~/.staticperl/bin/perl Makefile.PL
      make
      make install
  8. Build staticperl, CD into App-Staticperl and issue
  9. ./staticperl.sh mkperl --incglob '*' --static
  10. A new executable ‘perl’ should be generated in cwd, test this perl by running it against test.pl
  11. ./perl ../test.pl
    53616c7465645f5f477a787c68a095cb9ba06fb7768140a623a2670aa1c3a4f553d3e64dc16fc5707c6c9a6eac5dcf32
    1234567890123456
    41f813eca9ddd189f7ff3280ada72c8a
    1234567890123456
  12. If the above match then the new single executable perl has been generated successfully

Posted in Linux, Perl. Tagged with , , , .

printf (or other I/O) on MSP430 and Code Composer 5

Today I came across a funny problem: the following code would not print anything (in Code Composer you are supposed to get a console window that pops up and shows your the STDIO stuff).

#include <stdio.h>

int main() {
	printf("Hello!\n");

	return 0;
}

Turns out this is because printf and other I/O functions require a huge stack and heap size. To fix this, go to Project -> Properties -> Build -> MSP430 Linker -> Basic Options -> set stack size to 500 and set heap size to 500

Posted in MSP430. Tagged with , , , .

Setting up DD-WRT on a Linksys E3000

Recently had the chance to install DD-WRT on a Linksys E3000 router so that I could use the USB port on it to share a printer. Here are the steps that worked for me:

Installing DD-WRT onto the E3000


Credit to post on this link. I’m reposting this thread for archiving purposes.


Posted by: Sean Cullinan 5/15/2011 10:33 PM
In this article I will explain how to get a Linksys E3000 setup with DD-WRT Mega nv60k firmware. I originally wrote this article so that we could use the router as an OpenVPN client to the HMA Pro! VPN service, but after playing around with this version of the firmware I discovered that I couldn’t make this version work with OpenVPN. So I had to roll back to an older version of DD-WRT to get things working. If your goal is to use your Linksys E3000 router as an OpenVPN client please check out my other post instead.

The usual disclaimer applies with these instructions. These instructions will have you flashing the firmware on your router, always a risky proposition. You may brick your router. You may void the warranty. If you do brick your router or otherwise break it do not hold myself or blendblog.net responsible! I have vetted these instructions and they do work, but there is always risk when doing these things, and that risk is on you!

Please note that you will lose all your existing router settings by following this procedure. You cannot restore the factory settings from the factory firmware to the DD-WRT firmware that we will be installing. So write them down an

Now that that’s out of the way let’s get started:

Doing a full reset (30/30/30)
The first thing we are going to do is a full reset before proceeding. This is often called a “30/30/30” reset and it ensures that the router is totally “clean” without getting into the details.
1) Plug in the Linksys E-3000 router. Let it boot up, when the wifi and power light are on continue.
2) Using a ballpoint pen, paper clip or simliar instrument press and hold the reset button for 30 seconds (don’t cheat)
3) Continue holding the reset button while you unplug the router. Wait 30 seconds…continue holding!
4) Continue holding the reset button while you plug the router back in. Wait 30 seconds. You can now let go!

Connnecting the router to your PC and logging in
1) Plug the ethernet port of your computer to port 1 on the Linksys router.
2) Wait 10 seconds to get an IP address (default should be 192.168.1.1)
3) On your computer navigate to http://192.168.1.1 in your web browser.
4) Enter in “admin” as the username and “admin” as the password (these are the defaults). You should now be logged in!

Installing the Trailed Initial Flash Build of DD-WRT for the Linksys E3000
We need to first install this build of DD-WRT in order to upgrade to the “Mega build” of DD-WRT that contains the OpenVPN client in it.
1) Download the Trailed Initial Flash Build of DD-WRT (1-dd-wrt.v24-14853_NEWD-2_K2.6_std_usb_ftp-e3000.bin).
2) Navigate to the “Administration” tab in the router’s web interface.
3) Click the “Firmware Upgrade” sub tab in the router’s web interface.
4) Click the “Browse” button and select the file that you downloaded in step 1 which will be called 1-dd-wrt.v24-14853_NEWD-2_K2.6_std_usb_ftp-e3000.bin.
5) Press the “Start Upgrade” button. DO NOT POWER OFF YOUR ROUTER DURING THE UPGRADE!
6) When complete you will get a message that says “Upgrade is successful.” Press the Continue button and let the router reboot. Your browser may “timeout” which is ok.

Doing another full reset (30/30/30)
Just like before, you have to do another full reset after each firmware flash so get comfortable with this process!
1) Let the Linksys router boot up, when the wifi, ethernet port 1, and power light are on continue.
2) Unplug the Ethernet cable from port 1
3) Using a ballpoint pen, paper clip or simliar instrument press and hold the reset button for 30 seconds (don’t cheat)
3) Continue holding the reset button while you unplug the router. Wait 30 seconds…continue holding!
4) Continue holding the reset button while you plug the router back in. Wait 30 seconds. You can now let go!
Re-Connnecting the router to your PC and logging in
Now that DD-WRT is cleanly installed lets login and see it!
1) Plug the ethernet port of your computer to port 1 on the Linksys router.
2) Wait 10 seconds to get an IP address (default should be 192.168.1.1)
3) On your computer navigate to http://192.168.1.1 in your web browser.
4) DD-WRT will prompt you to enter in a router username and password. Use whatever you’d like but dont’ forget it! I had to do this twice, the first time it failed for some reason…nothing to worry about.
5) Click on the setup tab and you will be prompted to enter the new username and password you created in step 4. Do so.

Installing the “Mini” build of DD-WRT
1) Download the Mini Build of DD-WRT for the Linksys E-3000 (2-dd-wrt.v24-16758_NEWD-2_K2.6_mini-e3000.bin).
2) Click the “Administration Tab” in the DD-WRT web interface
3) Click the “Firmware Upgrade” sub tab in the DD-WRT web interface
4) Click the “Browse” button and select the file that you downloaded in step 1 which will be called 2-dd-wrt.v24-16758_NEWD-2_K2.6_mini-e3000.bin.
5) Press the “Upgrade” button. It will count down from 300 although at some point the browser. DO NOT POWER OFF YOUR ROUTER DURING THE UPGRADE!
6) When complete you will get notification that the “Upgrade was successful…rebooting.” Let it reboot.

Doing another full reset (30/30/30)
Just like before, you have to do another full reset after each firmware flash so get comfortable with this process!
1) Let the Linksys router boot up, when the wifi, ethernet port 1, and power light are on continue.
2) Unplug the Ethernet cable from port 1
3) Using a ballpoint pen, paper clip or simliar instrument press and hold the reset button for 30 seconds (don’t cheat)
4) Continue holding the reset button while you unplug the router. Wait 30 seconds…continue holding!
5) Continue holding the reset button while you plug the router back in. Wait 30 seconds. You can now let go!

Re-Connnecting the router to your PC and logging in
Now that DD-WRT mini is cleanly installed lets login and see it!
1) Plug the ethernet port of your computer to port 1 on the Linksys router.
2) Wait 10 seconds to get an IP address (default should be 192.168.1.1)
3) On your computer navigate to http://192.168.1.1 in your web browser.
4) DD-WRT will prompt you to enter in a router username and password. Use whatever you’d like but dont’ forget it!

Installing the “Mega” build of DD-WRT
1) Download the Mega Build of DD-WRT for the Linksys E-3000 (3-dd-wrt.v24-16758_NEWD-2_K2.6_mega-nv60k.bin).
2) Click the “Administration Tab” in the DD-WRT web interface
3) Click the “Firmware Upgrade” sub tab in the DD-WRT web interface
4) Click the “Browse” button and select the file that you downloaded in step 1 which will be called 3-dd-wrt.v24-16758_NEWD-2_K2.6_mega-nv60k.bin.
5) Press the “Upgrade” button. It will count down from 300 although at some point the browser. DO NOT POWER OFF YOUR ROUTER DURING THE UPGRADE!
6) When complete you will get notification that the “Upgrade was successful…rebooting.” Let it reboot.

Re-Connnecting the router to your PC and logging in
Now that DD-WRT mini is cleanly installed lets login and see it!
1) Plug the ethernet port of your computer to port 1 on the Linksys router.
2) Wait 10 seconds to get an IP address (default should be 192.168.1.1)
3) On your computer navigate to http://192.168.1.1 in your web browser.
4) DD-WRT will prompt you to enter in a router username and password. Use whatever you’d like but dont’ forget it!


Setting up Printer


Credit to post on this link. I’m reposting this thread for archiving purposes.


On the web interface of the router (http://192.168.1.1):
Enable “Core USB Support”, “USB 1.1 Support (UHCI)”, “USB 1.1 Support (OHCI)”, “USB 2.0 Support”, “USB Printer Support” on the Services tab (all items under “USB Support” except for “USB Storage Support”). Note that the router did not recognize my printer if I left the USB 1.1 drivers unselected. This even though the printer supports USB 2.0.
It is *not* necesary to enable JFFS2 support via Administration, Management
Check that Secure Shell is enabled via Services, Service. SSHd and Password Login must be enabled
Connect your printer to the router
Reboot the router via Administration, Reboot Router
Via an ssh client (for example putty under Windows) connect via SSH on port 22 to the router:
login as: root
password:
check if your printer was recognized:

 root@my-ddwrt-router:~# dmesg | grep usb
 usbcore: registered new interface driver usbfs
 usbcore: registered new interface driver hub
 usbcore: registered new device driver usb
 usb usb1: configuration #1 chosen from 1 choice
 usb usb2: configuration #1 chosen from 1 choice
 usb 2-1: new full speed USB device using ohci_hcd and address 2
 usb 2-1: configuration #1 chosen from 1 choice
 usblp0: USB Bidirectional printer dev 2 if 0 alt 1 proto 2 vid 0x047E pid 0x1001
 usbcore: registered new interface driver usblp

This indicates that a printer is detected on the USB port
Now enter

 root@my-ddwrt-router:~# netstat -an
 Active Internet connections (servers and established)
 Proto Recv-Q Send-Q Local Address           Foreign Address         State
 tcp        0      0 0.0.0.0:9100            0.0.0.0:*               LISTEN
 tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN
 tcp        0      0 0.0.0.0:53              0.0.0.0:*               LISTEN
 tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN
 tcp        0    268 192.168.1.1:22          192.168.1.118:53385     ESTABLISHED
 tcp        0      0 192.168.1.1:80          192.168.1.118:53547     TIME_WAIT
 tcp        0      0 192.168.1.1:80          192.168.1.118:53538     TIME_WAIT
 tcp        0      0 192.168.1.1:80          192.168.1.118:53545     TIME_WAIT
 tcp        0      0 192.168.1.1:80          192.168.1.118:53548     TIME_WAIT
 tcp        0      0 192.168.1.1:80          192.168.1.118:53543     TIME_WAIT
 tcp        0      0 192.168.1.1:80          192.168.1.118:53540     TIME_WAIT
 tcp        0      0 192.168.1.1:80          192.168.1.118:53544     TIME_WAIT
 tcp        0      0 192.168.1.1:80          192.168.1.118:53541     TIME_WAIT
 tcp        0      0 192.168.1.1:80          192.168.1.118:53542     TIME_WAIT
 tcp        0      0 192.168.1.1:80          192.168.1.118:53546     TIME_WAIT
 udp       0      0 127.0.0.1:34954         0.0.0.0:*
 udp       0      0 0.0.0.0:53              0.0.0.0:*
 udp       0      0 0.0.0.0:67              0.0.0.0:*
 raw       0      0 0.0.0.0:255             0.0.0.0:*               255
 Active UNIX domain sockets (servers and established)
 Proto RefCnt Flags       Type       State         I-Node Path
 unix  3      [ ]         STREAM     CONNECTED       1178
 unix  3      [ ]         STREAM     CONNECTED       1177
 unix  2      [ ]         DGRAM                      1161

We are especially interested in the line
tcp 0 0 0.0.0.0:9100 0.0.0.0:* LISTEN
It is saying that a service via tcp is listening on port 9100
And at last enter

 root@my-ddwrt-router:~# ps | grep p9100d
 927 root      1108 S    p9100d -f /dev/lp0 0 -t 5

This also indicates that a process p9100d is running looking at port /dev/lp0 which is a printer port
You don’t have to install anything via ipkg or any other script. Everything is installed by default. So if you don’t have the expertise to ssh to your router, don’t despair, it is only to make sure that your router recognises your printer on the USB port.
To install the printer under Windows, use the following procedure:
Windows 7
Open Control Panel, Devices and Printers
Choose Add a printer
Add a local printer
Create a new port
Type of port: Standard TCP/IP Port
Hostname or IP address: 192.168.1.1
Make sure that the checkbox to query the printer and select a driver is not checked
Wait until the detection is done. It will say that the device is not found. Don’t despair
Choose Custom and then click Settings
Make sure that Protocol Raw is selected and Port 9100 is entered. That will be proposed.
Leave all other settings also as they were and press OK
Click Next.
Choose the printer driver for your printer.
Click Next
Give your printer a name
You don’t have to share the printer
Next
You can set it as default printer
Finish
Other
http://uis.georgetown.edu/software/documentation/winxp/winxp.network.printer.html
http://docs.info.apple.com/article.html?path=Mac/10.5/en/9031.html
Don’t forget that your routers default address is 192.168.1.1 and its port is 9100

Posted in Technology. Tagged with , , .

SVN revert repository to a previous revision

We recently had a problem where the head revision on the repository had the majority of the content mixed up. To restore the repository to a previous revision, you first update the repository (make a backup copy first) and then do the following:

svn merge -c -[REV]

Or

if you are using TortiseSVN like me, to go the repository -> Show Log -> right click on the revision -> Revert to this revision

Once done commit the code as a new revision and all should be fixed

Posted in Technology. Tagged with , , , .

Android 50% width horizontal layout

Recently I needed to have percentage based layout (I wanted two ListViews side-by-side at 50% of the screen each). Below is an way to achieve it using LinearLayout with layout_weight:

<LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >
        
        <ListView
            android:id="@+id/lstPrev"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight=".50" />
        
        <ListView
            android:id="@+id/lstCur"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight=".50" />
       
</LinearLayout>

Notice that both ListViews have layout_width set to 0 and layout_weight set to .50 (for 50%)

Posted in Android. Tagged with , , , .

Drawing on Google Maps Android API v2

This post is a recipe for drawing various things on the Google MapView on Android. It assumes that you have a MapView (or MapFragment) set up per this post

Code below assumes that mGMap is the google map object, obtained from:

MapFragment mf = (MapFragment) (getFragmentManager().findFragmentById(R.id.displayMap));
mGMap = mf.getMap();

Draw Marker

// draw marker
MarkerOptions mp = new MarkerOptions();
mp.position(pos);
mp.title("Test Marker");
mp.draggable(false);
mGMap.addMarker(mp);

Center Camera on Location (and Animate)

// center camera
CameraPosition cp = new CameraPosition.Builder()
	.target(pos)
	.zoom(15)
	.tilt(45)
	.build();
mGMap.animateCamera(CameraUpdateFactory.newCameraPosition(cp));

Draw Line

// draw line
if (prevPos != null) {
	mGMap.addPolyline(new PolylineOptions()
	.add(prevPos, pos)
	.width(5)
	.color(Color.BLUE)
    );
}

Posted in Android. Tagged with , , , .

Using MapView within Fragment under Google Maps Android API v2.0

There is surprisingly little amount of documentation on how to use the MapView from Googla Maps Android API v2. Especially from within a fragment. Below is a quick code example on how to get a MapView up and running inside a fragment (I am not using MapFragment so I can retain some extra control over the view).

** The guide assumes that you know how to use fragments with ViewPager

Relevant documents:


MapFragment.java

public class MapFragment extends Fragment {
	
	MapView m;
	
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, 
			Bundle savedInstanceState) {
		// inflat and return the layout
		View v = inflater.inflate(R.layout.map_fragment, container, false);
		m = (MapView) v.findViewById(R.id.mapView);
		m.onCreate(savedInstanceState);
		
		return v;
	}
	
	@Override
	public void onResume() {
		super.onResume();
		m.onResume();
	}
	
	@Override
	public void onPause() {
		super.onPause();
		m.onPause();
	}
	
	@Override
	public void onDestroy() {
		super.onDestroy();
		m.onDestroy();
	}
	
	@Override
	public void onLowMemory() {
		super.onLowMemory();
		m.onLowMemory();
	}
}

Notice that the map’s various life cycle related methods much be called by overriding the default of what a fragment has.

map_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<com.google.android.gms.maps.MapView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/mapView" />

Posted in Android, Java. Tagged with , , , .