Friday, January 25, 2013

Dynamic DNS on OpenWrt


  1. Search the download area for your version of OpenWrt's packages folder
  2. Then use your browser's find in page and look for "DDNS"
  3. There will be three hits; the first two start with:
    luci-ddns
    ddns-scripts
  4. SCP these files to the router (I use WinSCP).
  5. SSH to the router (I use Putty) and type:
    opkg install ddns{tab} luci-{tab}
  6. Now you can edit the DDNS settings either via the web browser (click the services tab) or
    vi /etc/config/ddns
  7. Make sure to click the "Enable" checkbox and set enabled equal to 1 in the config file!
  8. At this point you could stop and hope it works, but more likely than not it wont.
  9. Try to run the update script and see what happens:
    /usr/lib/ddns/dynamic_dns_updater.sh myddns
  10. This script uses BusyBox's wget to call the DDNS service.  However, whoever put the sed replacements together must use "1234" as their password because just about any special character gets escaped wrong and break DDNS updating.

    Even my email address did not work.

    Luckily with dyndns you can use a username as well-- I set mine to have no special characters.

    There are a number of fixes you can make to the script instead (see first 3 results).



Thursday, June 28, 2012

Cross Site Scripting PHP Proxy

I needed to access a REST web service from jQuery, but Chrome would throw an error during the ajax call due to the "origin" policy.  It's possible to setup a CORS filter with Tomcat and Apache, but that sounded like a lot of work.

Instead, if you can use PHP, just download the following PHP proxy:
https://github.com/developerforce/Force.com-JavaScript-REST-Toolkit/blob/master/proxy.php

Two changes are needed:

  1. Edit line 176 such that it reads  $url_query_param = 'url';
  2. Either fix the regexp at lines 172 and 173 which checks that the call is to sales force.com (set it to match your website) or  comment out lines 206 to 212 (potentially dangerous).
Now your $.ajax call needs to be modified so that the target url is part of the url.  Everything else is seamless.  See below.

 
 var req = $.ajax({
    type: 'GET',
    contentType: 'application/json',
    mimeType: 'application/json',
    url: 'http://proxy-server/app/proxy.php?mode=native&url=http://api-server/api/object/'+$("#objectID").val(),
    dataType: 'json',
    success: function(data, textStatus, jqXHR) {
 alert("Got data successfully");
 $('#responseData').text(JSON.stringify(data));
 },
    error: function(xhr, textStatus, error) {
 alert("Error: " + textStatus);
 } 
  });
That's it!

Thursday, March 15, 2012

Formatting and Parsing Java Dates

My favorite page on this topic so far is here.

Monday, March 12, 2012

Fun Android camera gotcha

Android's camera object includes a method called takePicture which takes 3 callbacks as arguments:
1) shutter callback
2) raw callback
3) jpeg callback

The shutter callback occurs roughly when the shutter sound occurs in the stock camera.

Raw callback and jpeg callback occur when camera image data is available. Well, RAW > JPEG, right? So why not just implement RAW callback and skip JPEG callback? If you code up the RAW callback, you'll find that you can't get an image from the returned data. The object is non-null, but upon further inspection has zero length. What did I do wrong? you'll think. Actually, nothing, it just doesn't work. Never has. Yet it's still there in the libraries and in the documentation after years and years, without any note or anything that it doesn't freaking work. Huh? (typical Android).

Monday, March 05, 2012

Sending Multipart Form Data from Java (and receiving it via PHP)

If you want to send binary data and some parameters, you'll need to execute a POST with the content type of multipart/form-data. This takes a different format than usual HTTP requests. The secret to sending multipart form data is sending the right number of line endings. Rather than explain it, here's the code.
String lineEnd = "\r\n"; 
String twoHyphens = "--";
String boundary = "*****";
int bytesRead, bytesAvailable, bufferSize;
byte[] buffer;
int maxBufferSize = 1*1024*1024;
File temp_file = new File("foo.txt");
// open a URL connection
URL url = new URL(urlString);

// Open a HTTP connection to the URL
conn = (HttpURLConnection) url.openConnection();

// Allow Inputs
conn.setDoInput(true);

// Allow Outputs
conn.setDoOutput(true);

// Don't use a cached copy.
conn.setUseCaches(false);

// Use a post method.
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary="+boundary);

dos = new DataOutputStream( conn.getOutputStream() );

// Send parameter #1
dos.writeBytes(twoHyphens + boundary + lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\"param1\"" + lineEnd + lineEnd);
dos.writeBytes("foo1" + lineEnd);

// Send parameter #2
dos.writeBytes(twoHyphens + boundary + lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\"param2\"" + lineEnd + lineEnd);
dos.writeBytes("foo2" + lineEnd);

// Send a binary file
dos.writeBytes(twoHyphens + boundary + lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\"uploadedfile\";filename=\"" + temp_file.getName() +"\"" + lineEnd);
dos.writeBytes(lineEnd);

// create a buffer of maximum size

bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];

// read file and write it into form...

bytesRead = fileInputStream.read(buffer, 0, bufferSize);

while (bytesRead > 0)
{
dos.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}

// send multipart form data necesssary after file data...

dos.writeBytes(lineEnd);
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);

// close streams
fileInputStream.close();
dos.flush();
dos.close();


Ok, now how to read this on the other end? Here's how to do it via PHP:
// Make sure a binary file is attached to the POST
if(!$_FILES) {
echo "No file!"
}

$id = $_FILES['uploadedfile']['name'];
move_uploaded_file($_FILES['uploadedfile']['tmp_name'], "/permanent/location".$id);

// Uncomment next line to print out the array to a file
// file_put_contents("/permanent/location/".$id.".debug.txt", print_r($_POST, true));
$param1="";
$param2="";
if(isset($arguments['param1'])) {
$lat = $arguments['param1'];
}
if(isset($arguments['param2'])) {
$lon = $arguments['param2'];
}
echo "Uploaded " . $id . " with param1=" . $param1 . " and param2=" . $param2;

Android ProgressDialog and Threads

Many tasks require an application to get or post data from/to some web service. Since internet communication can be quick or quite lengthy, it's necessary to notify the user that some work is occurring. Android's ProgressDialog gives you two options: a dialog with a bar (like a copy dialog on Windows) or a spinner dialog (typical for Ajax web apps).

Unfortunately, using the progress dialog can be painful. Frustratingly, many tutorials show you how to instantiate a ProgressDialog but not how to use it properly, failing to mention that if you make a blocking call on the UI thread (like an HTTP request), the ProgressDialog will never actually appear. After 2 seconds, the Android OS will think your app has frozen and kill it. Great.

Many forum posts suggest using Android's AsyncTask to execute the "work" in the background (AsyncTask is supposed to be easier to use than creating a new thread), but I've found AsyncTask to be more headache than help. Just create a thread. It's not hard.

FYI, ProgressDialog requires a context (the calling activity), a message to display, and a handler to do some work. Your handler can only receive ONE variable, so I tend to use a HashMap so I can pass multiple bits of data.

I've come up with a pattern that I've reused and works well. Here we go!

  1. Create a thread class.

  2. public class WorkerThread extends Thread {
    private ProgressDialog dialog;
    private Handler handler;
    private HashMap messageData = new HashMap();

    // .. put your constructor etc here ...
    public WorkerThread(ProgressDialog dialog, Handler handler) {
    this.dialog = dialog;
    this.handler = handler;
    }

    public void run() {
    // Var to keep track of whether the work succeeded or not
    Boolean status = true;
    // ... do some work here ...

    // If an error occurred...
    if(error) {
    status = false;
    messageData.put("message", "Error message goes here");
    }
    messageData.put("status", status);

    // Send a message back to calling activity
    handler.obtainMessage(0x2a, messageData).sendToTarget();

    // Dismiss dialog
    if (dialog != null && dialog.isShowing())
    dialog.dismiss();
    }

    // Clean up if the thread is cancelled
    public void cancel() {
    messageData.put("status", false);
    handler.obtainMessage(0x2a, messageData).sendToTarget();
    if (dialog != null && dialog.isShowing())
    dialog.dismiss();
    }
    }
  3. Add a thread and a null handler to your activity.
  4. WorkerThread WorkerThreadInstance = null;
    Handler handler = null;
  5. Create the ProgressDialog in your Activity's onCreate

  6. ProgressDialog workDialog = ProgressDialog.show(this, "", "Working...", true);
  7. Create a handler.

  8.   // Handle response from the worker thread
    handler = new Handler() {
    @SuppressWarnings("unchecked")
    @Override
    public void handleMessage(Message msg) {
    super.handleMessage(msg);
    HashMap data = (HashMap) msg.obj;
    Boolean status = (Boolean) data.get("status");

    if (status==true) {// if successful
    Toast.makeText(getApplicationContext(), "Work was successful",
    2000).show();
    // Process return data here
    // Uncomment the next line if your activity should end once processing is done
    //finish();
    } else {
    if(data.get("message")!=null) {
    Toast.makeText(getApplicationContext(), "Work failed!" + data.get("message") ,
    3000).show();
    }
    // Uncomment the next line if your activity should end after an error
    //finish();
    }
    }
    };
  9. Instantiate your worker thread

  10.   // Create an instance of the worker thread
    WorkerThreadInstance = new WorkerThread(workDialog, handler);
    WorkerThreadInstance.start();
  11. Implement onPause for your activity to stop the worker thread if the activity is paused(and possibly onResume-- though be aware that onResume will be called before onCreate)

  12.  @Override
    public void onPause() {
    super.onPause();

    if (WorkerThreadInstance != null) {
    WorkerThreadInstance.cancel();

    // Mark thread for deletion by GC or there will be a memory leak
    WorkerThreadInstance = null;
    }
    }

Android ListView

Android includes a ListView element designed to make it easy to create lists. But it's not as straightforward as adding a ListView element and then calling some add function. You will need to create an "ArrayAdapter" and a couple of layout XML files, unless you want to create a simple list of strings (change your activity from extending Activity to ListActivity and use the default array adapter).

Rather than explain the process, I refer you to a great tutorial which be found here.

Tuesday, November 08, 2011

Using an AVR ISP Mk II with the Arduino IDE

It is possible to program an AVR on an Arduino board using the AVR ISP Mk II programmer directly from the Arduino IDE. The process is faster and an Arduino bootloader is not required to be loaded on the AVR, so you can program AVRs purchased from Mouser, Digikey, etc and then transfer them to a permanent circuit board.

Simply edit boards.txt (location varies-- try searching your root arduino software folder) and add:


atmega328ii.name=Arduino Duemilanove ATmega328 AVR ISP Mk II

atmega328ii.upload.protocol=stk500
atmega328ii.upload.maximum_size=30720
atmega328ii.upload.speed=57600

atmega328ii.upload.using=avrispmkii
atmega328ii.build.mcu=atmega328p
atmega328ii.build.f_cpu=16000000L
atmega328ii.build.core=arduino

##############################################################


Then you can go to Tools>Boards> and select ATMega 328 ISP from the list. Attach your AVR ISP Mk II to the Arduino board (make sure the orientation is correct-- both of the AVR and the ISP cable). Hit program as normal. Voila!

Friday, October 14, 2011

CSS Radial Backgrounds

CSS3 allows you to make radial gradients fairly easily. Unfortunately, you need six lines to cover all the browsers that support CSS3, but luckily all but the old webkit syntax are very similar.

http://www.impressivewebs.com/css3-radial-gradient-syntax/

Full Screen Background Image with CSS

Since the height attribute doesn't work so well in CSS backgrounds (100% will not actually cause your background image to scale to the full height of the window, for example), if you want a full screen background you'll have to go another route. Luckily, this solution is written up cleanly:
http://paulmason.name/blog/item/full-screen-background-image-pure-css-code

Simply copy #full-screen-background-image and you're good to go. The styling also works for DIVs.

Labels

Blog Archive

Contributors