Wednesday, November 23, 2011

memcpy and memmove

It is interesting to notice the difference between the memcpy and memmove when programming in C. 

While the memcpy copies the data byte-by-byte sequentially from source to destination, the memmove function copies the block of data to the source to the destination. The difference implies that the memcpy function can generate the repeating data results (see below) if the source data being copied happens to be overlapping with the destination data:

#include <stdio.h>
#include <string.h>


int main()
{
    char src1[] = "abcdefg";
    char src2[] = "abcdefg";
    char *dest1;
    char *dest2;
    
    if ((dest1 = (char*)malloc(8*sizeof(char))) == NULL
        || (dest2 = (char*)malloc(8*sizeof(char))) == NULL)
        exit(1);
    
    //memcpy src1 -> dest1
    memcpy(dest1, src1, 7);
    printf("memcpy\tsrc1:%s\tdest1:%s\n", src1, dest1);
    
    //memmove src2 -> dest2
    memmove(dest2, src2, 7);
    printf("memmove\tsrc2:%s\tdest2:%s\n", src2, dest2);
    
    //memcpy src1 -> src1+1
    memcpy(src1+1, src1, 6);
    printf("memcpy\tsrc1:%s\n", src1);
        
    //memmove src2 -> src2+1
    memmove(src2+1, src2, 6);
    printf("memmove\tsrc2:%s\n", src2);
    
    free (dest1);
    free (dest2);
    return 0;
}

The result would be:


memcpy  src1:abcdefg    dest1:abcdefg
memmove src2:abcdefg    dest2:abcdefg
memcpy  src1:aaaaaaa
memmove src2:aabcdef


Thus, memcpy should be used with caution when the data is overlapping with each other.  Specifically, the memmove works identically to memcpy if:
src_addr + length_copy < dest_addr or src_addr > dest_addr 
and it works reversely in the other way. So, the memmove can also be implemented as memmove2:


void * memmove2(void *dest, const void *src, size_t len)
{
    if (src != dest)
    {
        if ((const char*)src+len < dest || (const char*)src > dest)
            memcpy(dest, src, len);
        else
            while (len--)
                *((char*)dest+len) = *((const char*)src+len);
    }
    return dest;
}

If we compare the following code snippets, the running time are also different between:

    for (i = 0; i < 100000000; i++)
        memmove(dest, src, n);

and

    for (i = 0; i < 100000000; i++)
        memmove2(dest, src, n);


The results depend on the relationship between dest and src, where n denotes the length of string to be copied:

                dest < src | dest==src | dest > src | dest > src + n
    memmove         4.020       0.321       18.070      4.036
   memmove2         3.148       0.892       3.096       3.295

The running time is in second. It is obvious that while the memmove2 function outperforms the standard function in cases where dest!=src, the memmove is better when dest==src.


(Compiled using gcc 3.4.4)

Sunday, November 13, 2011

Use Mock GPS Location for Android Development - Part Two

In the first part of this topic, several simple methods for sending mock GPS location data to the device or emulator have been discussed. They are convenient when you need only test one GPS location at a time. However, when you want to test a consecutive points set (e.g. a route for a moving vehicle) for your app, these methods are not that handy. Therefore, in this part, two other simple ways for mock continuous GPS locations for testing your app are provided: one is using KML file, another way is writing a small app to provide the mock GPS locations updates.

Using KML on DDMS:

The easiest way to send a path of GPS points to the emulator is through the Location Controls in the DDMS for Android emulator. Just need a KML file for storing the path, and use DDMS to send this path of locations to the emulator at a certain interval.

1. Start the Google Earth desktop application and click on "Add" and then "Path" to draw the path:


2. "Cltr+S" to export the route as a kml file on to your disk;

3. Use a web tool (e.g.ge2adt) to convert that the Goolge Earth route into the Eclipse ADT compatible kml format; (here is the sample kml route file after the conversion)

Or, if you don't want to use Google Earth, the KML file format for the Android emulator is like:



4. Start the Android emulator and your GPS location app; Click on the "Load KML..." on the Location Controls field in the DDMS to load the path kml:

Using the MockLocationBuilder:

The following small app is to send the mock locations that a user has specified to the emulator (or real device). The app works like this:

1. Start the MockLocationBuilder and draw the path;
2. Start the test GPS;
3. Start the target app that use the test GPS's updates (e.g. Google Map on Android).



You can download the code from here.

The app supports:
1. Define the path
2. Generate the mock GPS updates loop around the path at regular interval
3. Work in the background (allow you to start the target app)

About the Code:

The MockLocationBuilder class extends the MapActivity class to display and manage the map:

public class MockLoctionBuilderActivity extends MapActivity
Then specify the location provider's name:

static private String mTestProvider = LocationManager.GPS_PROVIDER;
To add the mock location provider, you can use this function:

 private void addMockLocationManager() {
  mLocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
  if (mLocManager.getProvider(mTestProvider) == null)
  {
   mLocManager.addTestProvider(mTestProvider, false, false,
    false, false, false, false, false,
    android.location.Criteria.POWER_HIGH,
    android.location.Criteria.ACCURACY_FINE);
  }
  mLocManager.setTestProviderEnabled(mTestProvider, true);
 }


Note that you can only specify the provider to be LocationManager.GPS_PROVIDER on the emulator but not on a real device, because the addTestProvider method will throw the error for the provider named "gps". To use on the device, you can specify the mTestProvider as some other strings.

And set the mock location at a regular interval through this method:

 private void setMockLocation(double latitude, double longitude) {
  Location newLocation = new Location(mTestProvider);
  newLocation.setLatitude(latitude);
  newLocation.setLongitude(longitude);
  newLocation.setTime(System.currentTimeMillis());
  mLocManager.setTestProviderLocation(mTestProvider,
    newLocation);
 }

Note that the newLocation.setTime method set the timestamp when the new location is generated, which makes the location listener takes in it as an updated location.

Release the provider after the running by:

if (mLocManager.getProvider(mTestProvider) != null)
    mLocManager.removeTestProvider(mTestProvider);
 


PS: 1. On the device, remember that the system might setup the LocationManager.GPS_PROVIDER as the default provider, so that you cannot call the addTestProvider method on it. However, you can specify the test provider to be some other name and use the same test provider in the target app for location updates;

2. You may want to change the frequency of the GPS updates.


Ref:
This post provides more detailed discription of the important methods:
http://ballardhack.wordpress.com/2010/09/23/location-gps-and-automated-testing-on-android/