GPS using the Netduino

I recently blogged about using the Arduino board as a GPS data logger. I have been using this to collect geo-location data for the Truck Tracker application. In this post, I will explore using the Netduino for that purpose.

Meet the Netduino

Here is a photo of the Netduino board.

imageThere are more technical specs for the Netduino board on the Netduino site. The two features that stand out to me are:

  • Most of the Arduino shields are compatible with the Netduino. This means that many of the Arduino projects can be ported to the Netduino. In this post, we will look at porting the GPS shield used in the Arduino project to work with the Netduino.
  • The programming environment of the Netduino is the .NET Micro Framework (.NET MF). This allows your favorite flavor of Visual Studio to be used as your IDE.

Here is a photo of the GPS shield mounted to the Netduino.

image

Connections

If you built the GPS shield following the instructions on the ladyada site, then the following are the pin out connections that the Netduino will use to communicate with the GPS shield:

  • TX (Digital I/O Pin 0) – This is the transmit pin, data that comes from the GPS module with location data.
  • RX (Digital I/O Pin 1) – This is the receive pin, data that goes to the GPS module to configure it.
  • PWR (Digital I/O Pin 2) – This pin is connected to a transistor that controls power to the GPS. When this pin is set to LOW the GPS module turns on and when the pin is set to HIGH the GPS turns off.

Once the unit has power, the TX/RX pins are a serial port that is used to communicate with the GPS unit. Once power is applied, GPS data will begin being streamed from the GPS unit.

Basic Programming

The most basic Netduino code to connect and read data from the GPS serial port is shown below:

using System;
using System.IO.Ports;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;

namespace GpsLogger
{
    public class Program
    {
        public static void Main()
        {
            // write your code here
            SerialPort serialPort = new SerialPort("COM1", 4800, Parity.None, 8, StopBits.One);
            serialPort.Open();

            // pin D2 off = gps module turned on
            OutputPort powerPin = new OutputPort(Pins.GPIO_PIN_D2, false);

            while (true)
            {
                int bytesToRead = serialPort.BytesToRead;
                if (bytesToRead > 0)
                {
                    // get the waiting data
                    byte[] buffer = new byte[bytesToRead];
                    serialPort.Read(buffer, 0, buffer.Length);
                    // print out our received data
                    Debug.Print(new String(System.Text.Encoding.UTF8.GetChars(buffer)));
                }

                Thread.Sleep(100); // wait a bit so we get a few bytes at a time...
            }
        }
    }
}

This code is taken from the one of the posts on the very active Netduino community forum. The first thing you will notice is a few new C# using statements. There are a few from the Microsoft.SPOT namespace. SPOT stands for “smart personal object technology” and was developed by Microsoft to personalize household electronics and other everyday devices. Microsoft has extended this namespace to include a range of essential hardware features that programmers can use when developing embedded device firmware. There are also a couple of using statements with a Secretlabs.NETMF.Hardware namespace. Secret Labs is the company that is developing the Netduino hardware and manages the developer community.

The first two lines of the code begins serial communications with the GPS. The Netduino firmware is setup so that “COM1” uses digital pins 0 / 1 for serial TX / RX. The next line of code applies power to the GPS unit. Finally the never ending while loop, reads and prints data to the debugger. Below is a screen shot of the debugger in action.

Did I mention the debugger? You can debug your Netduino embedded project just like you are used to in Visual Studio. Amazingly, break points, watches and live evaluations all work. Great job to who ever figured that out!

 

image

In the bottom right, you can see the debug output showing the serial data coming from the GPS unit.

A Refined Example

The above code is great to get you started reading the GPS data. There is a bit more work to be done to get a reusable GPS shield library. Here are the goals of this GPS library:

  • Encapsulate the GPS code into a few logical classes in a form that is reusable.
  • Take advantage of the Netduino’s support of events by creating an event that other parts of the application can subscribe. The event will be raised when ever new data is available.

Here is the new entry point that is using the library:

public static void Main()
{
    SerialPort serialPort = new SerialPort("COM1", 4800, Parity.None, 8, StopBits.One);
    
    OutputPort powerPin = new OutputPort(Pins.GPIO_PIN_D2, false);

    Reader gpsShield = new Reader(serialPort, 100, 1.0);
    gpsShield.GpsData += GpsShield_GpsData;
    gpsShield.Start();

    while (true)
    {
        // Do other processing here.
        //
        // Can stop the gps processing by calling...
        //  gpsShield.Stop();
        //
        // Restart by calling...
        //  gpsShield.Start();
        //
        Debug.Print("Main...");
        Thread.Sleep(10000);
    }
}

private static void GpsShield_GpsData(GpsPoint gpsPoint)
{
    Debug.Print("time: " + gpsPoint.Timestamp + "\tLat/Lng: " + gpsPoint.Latitude + "/" + gpsPoint.Longitude);
}

This code starts nearly the same by creating a ‘SerialPort’ and ‘OutputPort’ objects for serial communication and power. It uses constructor injection to create a GPS ‘Reader’ class with access to the ‘SerialPort’ object. The constructor takes three parameters: an instance of ‘SerialPort’, a timeout in milliseconds, and the minimum distance (in miles) between GPS data events. The timeout is used as a bit of a throttle for reading the serial port. The distance parameter allows the hardware take GPS observation points at a higher rate (one per second) and only raise data available events if the distance between the points is larger than this minimum. This allows data to be saved only when the new points are significantly apart thus allowing the SD card memory to be used more efficiently.

Next the “GpsData” event is subscribed to by the main application and an event handler is assigned. Currently, the data is only written to the debug console. This will eventually be the routine used to persist the data to the SD memory card. Notice the data being passed to the event is of type “GpsPoint”.

The ability to persist data to SD cards is currently being baked into the Netduino firmware. There is an update expected soon.

 

public class GpsPoint
{
    public DateTime Timestamp { get; set; }
    public double Latitude { get; set; }
    public double Longitude { get; set; }
    public double SpeedInKnots { get; set; }
    public double BearingInDegrees { get; set; }
}

Instances of “GpsPoint” contain the location information parsed from the GPS serial port.

The reader class is shown below:

public class Reader
{
    private readonly object _lock = new object();
    private readonly SerialPort _serialPort;
    private readonly int _timeOut;
    private readonly double _minDistanceBetweenPoints;
    private bool _isStarted;
    private Thread _processor;

    public delegate void LineProcessor(string line);

    public delegate void GpsDataProcessor(GpsPoint gpsPoint);

    public event LineProcessor RawLine;
    public event GpsDataProcessor GpsData;

    public bool IsStarted { get { return _isStarted; } }

    public Reader(SerialPort serialPort)
        : this(serialPort, 100, 0.0)
    {

    }
    public Reader(SerialPort serialPort, int timeOutBetweenReadsInMilliseconds, double minDistanceInMilesBetweenPoints)
    {
        _serialPort = serialPort;
        _timeOut = timeOutBetweenReadsInMilliseconds;
        _minDistanceBetweenPoints = minDistanceInMilesBetweenPoints;
    }

    public bool Start()
    {
        lock (_lock)
        {
            if(_isStarted)
            {
                return false;
            }
            _isStarted = true;
            _processor = new Thread(ThreadProc);
            _processor.Start();
        }
        return true;
    }

    public bool Stop()
    {
        lock (_lock)
        {
            if(!_isStarted)
            {
                return false;
            }
            _isStarted = false;
            if(!_processor.Join(5000))
            {
                _processor.Abort();
            }
            return true;
        }
    }

    private void ThreadProc()
    {
        Debug.Print("GPS thread started...");
        if(!_serialPort.IsOpen)
        {
            _serialPort.Open();
        }
        while (_isStarted)
        {
            int bytesToRead = _serialPort.BytesToRead;
            if (bytesToRead > 0)
            {
                byte[] buffer = new byte[bytesToRead];
                _serialPort.Read(buffer, 0, buffer.Length);
                try
                {
                    string temp = new string(System.Text.Encoding.UTF8.GetChars(buffer));
                    ProcessBytes(temp);
                }
                catch (Exception ex)
                {
                    // only process lines we can parse.
                    Debug.Print(ex.ToString());
                }
            }

            Thread.Sleep(_timeOut);
        }
        Debug.Print("GPS thread stopped...");
    }

    private string _data = string.Empty;
    private GpsPoint _lastPoint;
    private void ProcessBytes(string temp)
    {
        while (temp.IndexOf('\n') != -1)
        {
            string[] parts = temp.Split('\n');
            _data += parts[0];
            _data = _data.Trim();
            if (_data != string.Empty)
            {
                if (_data.IndexOf("$GPRMC") == 0)
                {
                    if(GpsData!=null)
                    {
                        GpsPoint gpsPoint = GprmcParser.Parse(_data);
                        if (gpsPoint != null)
                        {
                            bool isOk = true;
                            if(_lastPoint!=null)
                            {
                                double distance = GeoDistanceCalculator.DistanceInMiles(gpsPoint.Latitude, gpsPoint.Longitude,
                                                                               _lastPoint.Latitude, _lastPoint.Longitude);
                                double distInFeet = distance*5280;
                                Debug.Print("distance = " + distance + " mi (" + distInFeet + " feet)");
                                if(distance<_minDistanceBetweenPoints)
                                {
                                    // Too close to the last point....don't raise the event
                                    isOk = false;
                                }
                            }
                            _lastPoint = gpsPoint;

                            // Raise the event
                            if(isOk)
                            {
                                GpsData(gpsPoint);
                            }
                        }
                    }
                }
                if (RawLine != null)
                {
                    RawLine(_data);
                }
            }
            temp = parts[1];
            _data = string.Empty;
        }
        _data += temp;
    }
}

The public facing features include the CTOR, ‘Start’, and ‘Stop’. We previously discussed the CTOR parameters. The ‘Start’ method spins up a thread to read and process the GPS serial port. The ‘Stop’ method signals the thread to end and waits for it to join the thread requesting the stop.

I am not as sure of how the threading is working on the Netduino. This code seems to work on my computer, but may have issues that I am not aware of. The additional thread could easily be removed from the above code. I was thinking the main thread may have other processing (think a responsive UI) and pushing the GPS to its own thread may be necessary.

 

The ‘ThreadProc’ method is the main processing routine running in the separate thread. It is a loop that continues until the ‘_isStarted’ variable is set to ‘false’ by the ‘Stop’ method. The guts of the while loop reads and processes data from the GPS serial port.

The ‘ProcessBytes’ method process the serial port data. The GPS unit provides a stream of ‘GPS sentences’ that have a specified format. This method puts together the incoming bytes and processes completed lines (or sentences) once they are formed. The code above looks for only the “GPRMC” sentence. If one is found it is parsed using the following parser:

public class GprmcParser
{
    // Parse the GPRMC line
    //
    public static GpsPoint Parse(string line)
    {
        // $GPRMC,040302.663,A,3939.7,N,10506.6,W,0.27,358.86,200804,,*1A

        if(!IsCheckSumGood(line))
        {
            return null;
        }

        try
        {
            string[] parts = line.Split(',');
            if (parts.Length != 12)
            {
                return null;
            }

            if (parts[2] != "A")
            {
                return null;
            }

            string date = parts[9]; // UTC Date DDMMYY
            if (date.Length != 6)
            {
                return null;
            }
            int year = 2000 + int.Parse(date.Substring(4, 2));
            int month = int.Parse(date.Substring(2, 2));
            int day = int.Parse(date.Substring(0, 2));
            string time = parts[1]; // HHMMSS.XXX
            if (time.Length != 10)
            {
                return null;
            }
            int hour = int.Parse(time.Substring(0, 2));
            int minute = int.Parse(time.Substring(2, 2));
            int second = int.Parse(time.Substring(4, 2));
            int milliseconds = int.Parse(time.Substring(7, 3));
            DateTime utcTime = new DateTime(year, month, day, hour, minute, second, milliseconds);

            string lat = parts[3];  // HHMM.MMMM
            if (lat.Length != 9)
            {
                return null;
            }
            double latHours = double.Parse(lat.Substring(0, 2));
            double latMins = double.Parse(lat.Substring(2));
            double latitude = latHours + latMins / 60.0;
            if (parts[4] == "S")       // N or S
            {
                latitude = -latitude;
            }

            string lng = parts[5];  // HHHMM.M
            if (lng.Length != 10)
            {
                return null;
            }
            double lngHours = double.Parse(lng.Substring(0, 3));
            double lngMins = double.Parse(lng.Substring(3));
            double longitude = lngHours + lngMins / 60.0;
            if (parts[6] == "W")
            {
                longitude = -longitude;
            }

            double speed = double.Parse(parts[7]);
            double bearing = double.Parse(parts[8]);

            // Should probably validate check sum

            GpsPoint gpsPoint = new GpsPoint
                                  {
                                      BearingInDegrees = bearing,
                                      Latitude = latitude,
                                      Longitude = longitude,
                                      SpeedInKnots = speed,
                                      Timestamp = utcTime
                                  };
            return gpsPoint;
            
        }
        catch (Exception)
        {
            // One of our parses failed...ignore.
        }
        return null;
    }

    private static bool IsCheckSumGood(string sentence)
    {
        int index1 = sentence.IndexOf("$");
        int index2 = sentence.LastIndexOf("*");

        if (index1 != 0 || index2 != sentence.Length - 3 )
        {
            return false;
        }

        string checkSumString = sentence.Substring(index2 + 1, 2);
        int checkSum1 = Convert.ToInt32(checkSumString, 16);

        string valToCheck = sentence.Substring(index1 + 1, index2 - 1);
        char c = valToCheck[0];
        for(int i = 1;i<valToCheck.Length;i++)
        {
            c ^= valToCheck[i];
        }

        return checkSum1 == c;
    }
}

There are many available GPS sentence parsers out there. The above parser extracts the encoded information from the sentence and returns a ‘GpsPoint’ object (or null if there was a parsing error).

The processing code then calculates the distance between the new point and the previous point. This is done using the Haversine formula implemented by the following class:

public static class GeoDistanceCalculator
{
    private const double _earthRadiusInMiles = 3956.0;
    private const double _earthRadiusInKilometers = 6367.0;
    public static double DistanceInMiles(double lat1, double lng1, double lat2, double lng2)
    {
        return Distance(lat1, lng1, lat2, lng2, _earthRadiusInMiles);
    }
    public static double DistanceInKilometers(double lat1, double lng1, double lat2, double lng2)
    {
        return Distance(lat1, lng1, lat2, lng2, _earthRadiusInKilometers);
    }
    private static double Distance(double lat1, double lng1, double lat2, double lng2, double radius)
    {
        // Implements the Haversine formulat http://en.wikipedia.org/wiki/Haversine_formula
        //
        var lat = MathMF.ToRadians(lat2 - lat1);
        var lng = MathMF.ToRadians(lng2 - lng1);
        var sinLat = MathMF.Sin(0.5*lat);
        var sinLng = MathMF.Sin(0.5*lng);
        var cosLat1 = MathMF.Cos(MathMF.ToRadians(lat1));
        var cosLat2 = MathMF.Cos(MathMF.ToRadians(lat2));
        var h1 = sinLat*sinLat + cosLat1*cosLat2*sinLng*sinLng;
        var h2 = MathMF.Sqrt(h1);
        var h3 = 2 * MathMF.Asin(MathMF.Min(1, h2));
        return radius * h3;
    }
}

This code relies heavily on a math library (MathMF namespace) developed by Elze Kool. I slightly modified this library to use the System.Math functions where ever they were available. The changes that I made are shown below:

public static readonly double PI = System.Math.PI;

public static readonly double E = System.Math.E;


public static double Pow(double x, double y)
{
    return System.Math.Pow(x, y);
}

public static double Sqrt(double x)
{
    return System.Math.Pow(x, 0.5);
}

Not all the .NET framework is available in the .NET micro framework. One example is the ‘System.Math’ namespace. As the .NET micro framework grows up, I suspect that some of these namespaces will become available. Until then, we must rely on implementation made by the community.

If the distance is larger than the specified (in the CTOR) minimum, then the ‘GpsData’ event is raised. In addition a ‘RawLine’ event is available for every GPS sentence to be available.

Summary

Using the Netduino with the GPS shield was very straight-forward. I especially enjoy that I can use Visual Studio as my IDE. When the Netduino folks post an updated firmware that includes SD card features, I will continue this development and begin saving the data. I encourage anyone with a bit of curiosity to go get your self a Netduino and begin experimenting.

Did you enjoy this post?

Subscribe, comment, or share...

Comments [0] | Permalink | Save and Share
Wednesday, September 01, 2010 5:08:59 PM (Central America Standard Time, UTC-06:00) by rcravens

Truck Tracker Is Live

I have deployed the Truck Tracker application to here for now:

http://bobcravens.com/trucktracker/

The application is built using the following technologies:

  • ASP.NET MVC
  • Google Maps API v.3
  • jQuery
  • DotNetOpenAuth
  • MySQL
  • NHibernate
  • Ninject

The intent of the application is to create a “Nerd Dinner” like application that can be used as a reference to build your own application. I intend on making the source code available and will provide a link on the application site to access the source. I need to do review / cleanup the code added since the last spike and then I will post the code.

I will begin developing a service layer to allow you to push GPS data to the site programmatically. This will allow those of you who want to experiment with GPS to use the Truck Tracker application as a framework to display your data.

I will also be exploring how to get GPS data up to the site myself. The site already supports uploading GPS data files generated by the Arduino GPS Data Logger. I recently purchased a few Netduios and will try to get them working with the GPS module. The exciting thing is that the Netduinos are programmed using the Dot Net Micro Framework. I be looking to add a WiFi shield to the Netduino hardware. This should allow me to roam into a public or my home WiFi to push data automatically.

In addition, I have been wanting to create an iPhone application for some time and will be working on an application compatible with the Truck Tracker service layer soon after I publish the API. If would love having an experienced iPhone developer help with this a bit…any takers?

Adding your own truck (or vehicle) does require that you register via one of the OpenID or OAuth providers. Any trucks that you add can be marked as private.

Here is a screen shot of the home page. The list authentication providers that are available are shown at the top of the list. This screen shot is what you see before you log in.

image

The truck list on the left are all trucks that are marked as “public”. Once you log in you see the following screen:

image

Now the login area has been replaced with a menu bar that allows trucks to be managed. The list on the left now shows only trucks that you have added. Clicking on any of the trucks will display the current location of the truck and the last 24 hours of GPS points (note in the image below, this truck has not moved in the last 24 hours).

image

Once a truck has been selected a “Manage Truck” menu item appears. Clicking that item brings you to the following page:

image

The top part of this page allows you to update information about the truck. The bottom part allows you to upload the GPS data files generated by the Arduino Data Logger hardware.

Clicking the “Add Truck” menu item displays a page that allows you to add a new truck.

image

The bottom of the site includes a footer with links to the technologies used to build the site and tutorials on how to get started. This is where I will provide a link to the source code when it gets posted.

image

Summary

I would consider this release as an early “beta” release. I will be addressing issues as I become aware of them. If you find anything, please let me know.

Did you enjoy this post?

Subscribe, comment, or share...

Comments [0] | Permalink | Save and Share
Saturday, August 28, 2010 11:05:59 AM (Central America Standard Time, UTC-06:00) by rcravens

Making The Web Growl Using jQuery

I really like how the Growl application for the Mac works. It provides a notification framework that all applications can use. I often find my self needing to display notifications to the user in my web applications. For instance, when the user incorrectly fills out a form. Here is a screen shot of a simple ‘growl notification’.

imageThis is not complicated to add to an application. In the vein of “Don’t Repeat Yourself” I have put created a ‘growl package’ that can be downloaded below. For a live example check out the demo.

Demo Download

Growl Code

The download for the growl code consists of a JavaScript file and a CSS file. The JavaScript file contains the following code:

// Can't growl until the document is ready
var isGrowlReady = false;
$(document).ready(function () {
    isGrowlReady = true;
});

var growlMask;
var growlWrap;
var growlTitle;
var growlContent;
var isGrowlVisible = false;
function growl(title, msg) {
    // Recursively call growl until doc is ready
    while (!isGrowlReady) {
        setTimeout("growl('" + title + "', '" + msg + "')", 100);
        return;
    }

    // Ensure the growl HTML is in place and the events
    //  are hooked up. This code executes once.
    initGrowl();

    // Size the mask and growl window.
    sizeGrowl(true);

    // Animate the growl.
    growlMask
        .fadeTo("fast", 0.75, function () {
            isGrowlVisible = true;
            var scrollTop = $(document).scrollTop();
            growlTitle.html(title);
            growlContent.html(msg);
            growlWrap.show().animate({ "marginTop": scrollTop + 10 + "px" }, 500);
        });
}

function initGrowl() {
    if ($("#growl-mask").length == 0) {
        // Append growl HTML to body
        var growl = "<div id='growl-mask'></div><div id='growl-wrap'><h6 id='growl-title'></h6><div id='growl-content'></div></div>";
        $("body").append(growl);

        // Initialize global variables
        growlMask = $("#growl-mask");
        growlWrap = $("#growl-wrap");
        growlContent = $("#growl-content");
        growlTitle = $("#growl-title");

        // Hide growl on click event to the mask
        growlMask.click(function () {
            isGrowlVisible = false;
            growlWrap.fadeOut();
            growlMask.fadeOut();
        });
        // Reposition the growl if window is sized or scrolled
        $(window).resize(function () {
            if (isGrowlVisible) {
                growlMask.stop();
                growlWrap.stop();
                sizeGrowl(false);
            }
        });
        $(window).scroll(function () {
            if (isGrowlVisible) {
                growlMask.stop();
                growlWrap.stop();
                sizeGrowl(false);
            }
        });
    }
}

function sizeGrowl(hide) {
    // Collect some measurements
    var scrollLeft = $(document).scrollLeft();
    var scrollTop = $(document).scrollTop();
    var growlWidth = growlWrap.outerWidth();
    var growlHeight = growlWrap.outerHeight();
    var winWidth = $(window).width();
    var docHeight = $(document).height();
    var docWidth = $(document).width();

    // Calculate the notification position.
    var growlTop = hide ? scrollTop - growlHeight : scrollTop + 10;
    var growlLeft = scrollLeft + (winWidth - growlWidth) / 2;

    // Size and position the mask and the notification
    growlMask.css({ "width": docWidth + "px", "height": docHeight + "px" });
    growlWrap.css({ "margin-top": growlTop + "px", "left": growlLeft + "px" });
}

The first bit of JavaScript leverages the jQuery document ‘ready’ event to set a flag indicating the application is ready to support growls. This hook is necessary to support growls that originate in server side code (see ASP.NET MVC below for example).

There are two supporting functions in the JavaScript: ‘initGrowl’ and ‘sizeGrowl’. The ‘initGrowl’ function injects the necessary HTML to support the growl into the document, collects some quick references to the elements for use by other functions, and hooks up events. The windows ‘resize’ and ‘scroll’ events are used to keep the notification window positioned. The ‘sizeGrowl’ function takes a few measurements of the document and then sizes and positions the growl mask and notification window.

/* Growl
----------------------------------------------------------*/
#growl-mask
{
    background-color: #000;
    position: absolute;
    display: block;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    display: none;
}
#growl-wrap
{
    background-color: #fff;
    color: #000;
    min-width: 400px;
    margin: 0;
    display: none;
    position: absolute;
    top: 0;
    left: 0;
}
#growl-title
{
    text-align: center;
    color: #000;
}
#growl-content
{
    margin: 10px;
    border: 1px solid #333;
    padding: 30px;
}
#growl-content p
{
    margin-bottom: 10px;
}

The CSS above adds a bit of style. This will certainly need a touch up to blend into the application.

JavaScript Growls

To create a ‘growl’ notification using JavaScript simply include a link to the growl CSS and JavaScript then call the ‘growl’ function. Here is an example for validating a form:

<script type="text/javascript">
    $("#submit").click(function(){
        var msg = "";
        if($("#first").val()==""){
            msg += "<li><strong>First Name</strong> is required</li>"
        }
        if($("#last").val()==""){
            msg += "<li><strong>Last Name</strong> is required</li>"
        }
        if(msg != ""){
            msg = "<p>Please fix the following:</p><ul>" + msg + "</ul>";
            growl("Form Error", msg);
            return false;
        }
        return true;
    })
</script>

ASP.NET MVC Growls

Adding growl notifications to an ASP.NET MVC application involves a couple of steps. First add growl support to your controller base class (create one if you don’t have one).

public abstract class BaseController : Controller
{
    public void Growl(string title, string message)
    {
        TempData["Growl"] = title + "\t" + message;
    }
}

Notice that ‘TempData’ is used instead of ‘ViewData’. This allows growl notifications to live through redirects. Any controller that needs growl support should inherit from this base class.

public ActionResult Index()
{
    Growl("Test", "This is a test");

    return View();
}

Modify your Master Page to include links to the growl CSS and JavaScript. Finally add the following to your Master Page:

<% if(TempData.ContainsKey("Growl")) {
    string growl = (string)TempData["Growl"];
    string[] parts = growl.Split('\t');     
%>
<script type="text/javascript">
    growl('<%= parts[0] %>', '<%= parts[1] %>');
</script>
<% } %>

This will add a JavaScript call to the ‘growl’ function if a growl is present.

Summary

This is a pretty simple library. There are more features that can be added. If you give it a test drive, let me know how you like it.

Did you enjoy this post?

Subscribe, comment, or share...

Comments [1] | Permalink | Save and Share
Sunday, August 22, 2010 5:17:19 PM (Central America Standard Time, UTC-06:00) by rcravens

Create a GPS Data Logger Using The Arduino

Recently I have been developing an application that leverages GPS tracking. The high-level concept is to track mobile assets via GPS tracking. Each asset will have a GPS unit installed that logs its location. With the availability of low cost GPS this is becoming an every day reality. Many companies already use GPS to track and monitor their assets. In this post, we explore one option for the GPS tracking hardware.

There are really a two options for GPS tracking hardware: dedicated or shared GPS hardware. There are more and more devices (especially phones) that have GPS hardware. One solution is to write software that can be deployed to these devices and share the common GPS hardware. This is a great solution and I hope to explore this in later blog posts.

The other option is to develop your own dedicated hardware. Staring from scratch can be very daunting and expensive. However, there are a number of developer kits / boards that can spring board your development. In this post, we explore using the Arduino development kit to provide a quick and easy solution to our own dedicated hardware.

Meet The Arduino

After doing some investigation on the internet I selected the Arduino along with a GPS shield as the development hardware. The Arduino is a tool for the design and development of embedded computer systems. It consists of a simple open hardware design for a single-board microcontroller. The Duemilanove Arduino board is shown below:

image

There are two main reasons I chose the Arduino over other options:

  • The main board (shown above) is expanded by plugging in addition hardware called “shields”. There is an abundant number of shield options including a GPS Shield.
  • There is an existing ecosystem (suppliers, shields, libraries) and a strong developer community for the Arduino board and shields.

There is an embedded board that is compatible with the Arduino shields but is programmed using the .NET Micro Framework called the Netduino. The community is growing for this board, but I was not able to find the support that I (an embedded newbie) needed to get going. After I get experience with the Arduino and the GPS shield, I will try to convert it to use the Netduino.

The Arduino IDE

The IDE for Arduino development can be downloaded and come with many examples. Here is a screenshot of the IDE including example code to blink and LED (light emitting diode).

imageAt a basic level,  there are two main functions that a developer needs to “fill in” to get the Arduino working. The ‘setup’ function runs once. The ‘loop’ function repeats as long as the Arduino has power. The ‘setup’ / ‘loop’ combination creates a program called a ‘sketch’. Sketches are uploaded to the Arduino hardware via a USB cable. There are Windows and Mac versions of the IDE.

A developer creates a sketch, uploads it to the Arduino, and debugs the program using the USB as an umbilical cord. Once the program is ready to be deployed, the final version is uploaded and the Arduino can be run off of a 9 volt battery. This workflow is developer friendly and promotes experimentation.

GPS Shield

The GPS shield that I selected not only integrates with a GPS module but also includes data logging to a SD card. One surprise that I had was that the GPS shield looked like this when it came:

image Don’t let this scare you. The soldering is really easy and the instructions are extremely clear. After assembly, the shield looks like the following:

imageThe assembled shield is on the left and the GPS module is on the right. The GPS module plugs into the board and sits on the non-conductive double-sided taped four white pads.

image

On the bottom side of this board (not shown) is the SD card slot. This is used by the embedded system to persist the GPS data streamed from the GPS module.

Programming the Arduino / GPS Shield

The GPS shield site provides all the libraries and step-by-step instructions on programming the GPS shield / Arduino combination. Following these instructions, will have the hardware up and logging GPS data points in very little time. I did not run into any issues and will leave the details to the above site.

Testing

Once I assembled and programmed, I took the Arduino hardware on a test drive. I did not alter the provided Arduino sketch at all. By default, GPS points are logged to the SD card every second. There are suggestions to extend battery life by logging less often and shutting down diagnostic systems. The data is logged in text files. Opening one of these files you will find something like the following:

image

Each “GPRMC” line is the recommended minimum data set and is transmitted by most GPS devices. Each line can be decoded into: timestamp, latitude, longitude, speed, bearing, and status information.

At the GPS Visualizer site you can upload the file and have the data displayed on Google Maps. Here is a screen shot from my short trip:

image

Summary

I found the GPS unit was able to get a fix on the satellites even inside my house.  Overall I am very pleased with this hardware. I will be exploring a bit with this hardware and learning more about the software.

The ultimate goal is to have GPS hardware to collect data for the Truck Tracker application. There is a wireless shield that I think I can add to the board to allow the data logged to the SD card to be wirelessly posted to a web service. For now, I am okay manually uploading the text files.

I am extremely pleased with how easy it was to get started with the Arduino. If you are looking for a simple embedded solution, check out the many examples.

Did you enjoy this post?

Subscribe, comment, or share...

Comments [2] | Permalink | Save and Share
Sunday, August 15, 2010 12:51:03 PM (Central America Standard Time, UTC-06:00) by rcravens

OpenID and OAuth using DotNetOpenAuth in ASP.NET MVC

I have an ASP.NET MVC application that I would like to have both public and private features. Typically this is done by implementing an authentication / authorization gateway to gain access to the private features. Previously I blogged on an implementation using the ASP.NET membership / role providers with an XML-based membership. This blog post will detail how to use OpenID and OAuth to provide an authentication layer.

  • Authentication – You are who you say you are. The application knows your identity.
  • Authorization – Based upon your identity (via Authentication), the application provides access to features. Public access is provided to base features. Private access to enhanced features.

Here is a screencast showing the implementation in action.

For more information on OpenID and OAuth check out these links:

About OAuth

About OpenID

OAuth-OpenID: You’re barking up the wrong tree if you think they’re the same thing

OpenID / OAuth Workflow

The web application starts by presenting an area that allows the user to select between various OpenID / OAuth providers. The following screenshot shows this area.

imageThis provides a mechanism for the user to select one of the OpenId (OpenID, myOpenID, Google, Yahoo) or OAuth (Twitter) providers. Clicking on one of the providers starts the authentication process. Both OpenID and OAuth use a series of redirects to get the user authenticated. The key is that the authentication occurs on the provider’s site and that’s where the passwords are stored. Clicking one of the above providers results in a post to our application’s server. Our server then redirects to the provider’s server (after possible adding information to the post data). Here is a screenshot of the Twitter authentication page after the redirect to the Twitter provider.

imageClicking the “Allow” button causes post to the Twitter servers and another redirect. This time back to our application’s server. This redirect includes information about you that is supplied by the OpenID / OAuth providers. At minimum the redirect supplies a ‘username’ back to the application.

Our application can then look up the ‘username’ in the database to determine if the user is allowed access. Users that are allowed access will have the above login area swapped out for a panel that provides access to features only available to authenticated users. The following screenshot is an example.

imageNow that we have covered the workflow, let’s take a look at some code. Since we have just looked at the presentation layer, let’s start with the ASP.NET MVC views.

Views, CSS and JavaScript

The logic to display either the login screen or the panel with features for authenticated users is in the Master Page. The following code simply looks to determine if the user is authenticated. If not, it inserts the login partial view. Otherwise, it inserts in the panel partial view.

<div id="login">
    <% if (Request.IsAuthenticated) { %>
        <% Html.RenderPartial("_UserPanel"); %>
    <% } else { %> 
        <% Html.RenderPartial("_Login"); %>
    <% } %>
</div>

The panel partial view is provided by the following markup.

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<dynamic>" %>

<div id="user-panel-wrap">
    <span class="left"><%= Html.Encode( Session["FullName"] ) %></span>
    <span class="right">
        <ul>
            <li><%= Html.ActionLink("Add Truck", "Add", "Home") %></li>
            <li><%= Html.ActionLink("Log Off", "LogOff", "Account") %></li>
        </ul>
    </span>
</div>

The above code inserts a ‘div’ containing two ‘spans’. The first ‘span’ is ‘floated left’ (via the CSS class left) and contains the user’s full name. The full name is stored in the ‘Session’ dictionary by the Controller (more later). The second ‘span’ is ‘floated right’ (via the CSS class right) and contains an unordered list of links that provide access to features available to authenticated users only. Be sure to mark these action methods with the ‘Authorize’ attribute otherwise users could directly navigate to the URL and access the feature.

The following CSS styles the panel partial view.

.left   { float: left; }
.right  { float: right;}

#user-panel-wrap
{
    background-color: #000;
    margin: 10px 0;
    padding: 10px;
    color: #fff;
    text-align: right;
    overflow: auto;
}
#user-panel-wrap ul
{
    display: inline-block;
    list-style: none;
}
#user-panel-wrap ul li
{
    float: left;
    margin: 3px 10px;
}

The login partial view markup is shown below.

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<dynamic>" %>

<div id="openid-wrap">
    <form id="openid-form" method="post" action="<%= Url.Action("OpenId", "Account") %>">
        <p>Registered users can <strong>view and add private trucks</strong>. Otherwise feel free to browse
        the <strong>public</strong> trucks in the list below.</p>
        <p>Sign in using one of the providers below.</p>
        <div id="openid-providers">
            <ul>
                <li id="openid"></li>
                <li id="myopenid"></li>
                <li id="twitter"></li>
                <li id="google"></li>
                <li id="yahoo"></li>
            </ul>
        </div>
        <div id="other">
            <h3>Your OpendID Provider</h3>
            <input name="openIdUrl" id="openIdUrl" type="text" />
            <a id="signin">Sign In »</a>
        </div>
    </form>
</div>

The outer ‘div’ wraps a ‘form’ area that contains two child ‘div’ elements. The first child ‘div’ contains an unordered list of providers. This will be styled up using CSS and an image sprite to render the button images. The second child ‘div’ provides an ‘input’ text element that allows the user to enter the URL to any OpenID provider. The following CSS styles this partial view.

#openid-wrap
{
    background-color: #000;
    padding: 10px;
    color: #fff;
    margin-bottom: 10px;
}
#openid-wrap p
{
    font-size: 18px;
    text-align: center;
    margin: 5px 140px 14px;
    line-height: 30px;
}
#openid-wrap form
{
    margin: 3px;
}
#openid-wrap div#other
{
    display: none;
    text-align: center;
    margin: 10px 40px;
    padding: 10px;
    color: #000;
    background-color: #ddd;
    border: 1px solid #888;
    font-size: 18px;
}
#openid-wrap div#other h3
{
    color: #333;
    font-weight: bold;
    margin: 0 0 3px 0;
}
#openid-wrap input
{
    border: 2px solid #fba424;
    height: 36px;
    width: 500px;
}
#openid-wrap div#other a
{
    background-color: #333;
    color: #eee;
    border: 1px solid #666;
    padding: 10px 15px;
    display: inline-block;
}
#openid-wrap div#other a:hover
{
    background-color: #222;
    color: #fff;
    text-decoration: none;
    cursor: pointer;
}
#openid-providers
{
    overflow: auto;
    text-align: center;
}
#openid-providers ul
{
    display: inline-block;
    list-style: none;
}
#openid-providers li
{
    margin: 10px;
    padding: 0;
    float: left;
    width: 150px;
    height: 50px;
    background: transparent url('../images/openid_sprite.png') no-repeat 0 0;
}
li#openid       { background-position: 0 0; }
li#myopenid     { background-position: 0 -50px; }
li#twitter      { background-position: 0 -100px; }
li#facebook     { background-position: 0 -150px; }
li#google       { background-position: 0 -200px; }
li#yahoo        { background-position: 0 -250px; }
li#openid:hover       { background-position: -150px 0; cursor: pointer; }
li#myopenid:hover     { background-position: -150px -50px; cursor: pointer; }
li#twitter:hover      { background-position: -150px -100px; cursor: pointer; }
li#facebook:hover     { background-position: -150px -150px; cursor: pointer; }
li#google:hover       { background-position: -150px -200px; cursor: pointer; }
li#yahoo:hover        { background-position: -150px -250px; cursor: pointer; }

Towards the bottom the background image sprite for the provider buttons is set and individual offsets / hover effects are configured. Here is the image sprite that I am using.

openid_spriteThe left column is the normal button faces and the right column provides a subtly different (maybe too subtle) hover image.

The glue that makes this view work is the following JavaScript (using jQuery of course).

<script type="text/javascript">
    var providers = {
        myopenid: { action: '<%= Url.Action("OpenId", "Account") %>', url: 'http://myopenid.com' },
        twitter: { action: '<%= Url.Action("OAuth", "Account") %>' },
        facebook: { action: '<%= Url.Action("OpenId", "Account") %>', url: 'http://facebook.com' },
        google: { action: '<%= Url.Action("OpenId", "Account") %>', url: 'http://www.google.com/accounts/o8/id' },
        yahoo: { action: '<%= Url.Action("OpenId", "Account") %>', url: 'http://yahoo.com' }
    };
    $("#openid").click(function () {
        toggleOther();
    });
    $("#signin").click(function () {
        $("#openid-form").submit();
    });

    $("li").not("#openid").click(function () {
        $("#other").hide(500);
        isHidden = true;
        var id = $(this).attr("id");
        var provider = providers[id];
        if (provider.action != undefined) {
            $("#openid-form").attr("action", provider.action);
        }
        if (provider.url != undefined) {
            $("#openIdUrl").val(provider.url);
        }
        $("#openid-form").submit();
    });

    var isHidden = true;
    function toggleOther() {
        if (isHidden) {
            $("#other").slideDown(500);
        } else {
            $("#other").slideUp(500);
        }
        isHidden = !isHidden;
    }
    
</script>

The first bit of JavaScript creates a JSON object containing provider information. Each provider can have an ‘action’ and/or a ‘url’ member. The ‘action’ member defines the URL that the ‘form’ should post to when submitted. Notice there are different URLs for OpenID and OAuth. The ‘url’ member provides the URL to the OpenID provider.

The ‘toggleOther’ method (at the bottom) hides or shows the ‘div’ with the ID ‘other’ by using a slide up/down animation. The essence of the above JavaScript is to set the ‘input’ text box to contain the appropriate URL to the OpenID provider and then submit the form to the desired action method. This is done in the click handler for the ‘li’ elements and uses the JSON object.

Controller

Before discussing the action methods of the controller, you will need to get the DotNetOpenAuth library. Once you download it add a reference to it from your web application project. If you want to get twitter connected up be sure to also download the ‘TwitterConsumer’ and ‘InMemoryTokenManager’ implementations. These implementations are C# code files that you will need to add to your project as well.

I have named the controller ‘AccountController’ and the following code shows the constructor and private fields.

static private readonly OpenIdRelyingParty Openid = new OpenIdRelyingParty();
static private readonly InMemoryTokenManager TokenManager
        = new InMemoryTokenManager("consumerKey", "consumerSecret");

private readonly IFormsAuthentication _formsAuth;
private readonly IIntKeyedRepository<User> _userRepository;
private readonly IUnitOfWork _unitOfWork;
private readonly ILogger _logger;

public AccountController(
    IFormsAuthentication formsAuthentication, 
    IIntKeyedRepository<User> userRepository, 
    IUnitOfWork unitOfWork, 
    ILogger logger)
{
    _formsAuth = formsAuthentication;
    _userRepository = userRepository;
    _unitOfWork = unitOfWork;
    _logger = logger;
}

The application uses Ninject as a dependency injection container (thus the missing parameterless controller constructor). Ninject will provide implementations of all the constructor parameters. References to these parameters are then tucked away into the ‘readonly’ fields.

The ‘OpenIdRelyingParty’ instance is an object implemented by the DotNetOpenAuth library that is used for the OpenID authentication. The ‘InMemoryTokenManager’ is used for OAuth authentication with Twitter. Before you can use Twitter as an OAuth provider, you must register your app with Twitter. As a result of this registration Twitter will issue a ‘consumerKey’ and a ‘consumerSecret’ to substitute as the ‘InMemoryTokenManager’ parameters.

From our JavaScript discussions remember that OpenID and OAuth are submitted to two separate action methods. First let’s look at the action method that handles OpenID authentication.

public ActionResult OpenId(string openIdUrl)
{
    var response = Openid.GetResponse();
    if (response == null)
    {
        // User submitting Identifier
        Identifier id;
        if (Identifier.TryParse(openIdUrl, out id))
        {
            try
            {
                var request = Openid.CreateRequest(openIdUrl);
                var fetch = new FetchRequest();
                fetch.Attributes.AddRequired(WellKnownAttributes.Contact.Email);
                fetch.Attributes.AddRequired(WellKnownAttributes.Name.First);
                fetch.Attributes.AddRequired(WellKnownAttributes.Name.Last);
                request.AddExtension(fetch);
                return request.RedirectingResponse.AsActionResult();
            }
            catch (ProtocolException ex)
            {
                _logger.Error("OpenID Exception...", ex);
                return RedirectToAction("Login");
            }
        }
        _logger.Info("OpenID Error...invalid url. url='" + openIdUrl + "'");
        return RedirectToAction("Login");
    }

    // OpenID Provider sending assertion response
    switch (response.Status)
    {
        case AuthenticationStatus.Authenticated:
            var fetch = response.GetExtension<FetchResponse>();
            string firstName = "unknown";
            string lastName = "unknown";
            string email = "unknown";
            if(fetch!=null)
            {
                firstName = fetch.GetAttributeValue(WellKnownAttributes.Name.First);
                lastName = fetch.GetAttributeValue(WellKnownAttributes.Name.Last);
                email = fetch.GetAttributeValue(WellKnownAttributes.Contact.Email);
            }
            return CreateUser(response.FriendlyIdentifierForDisplay, firstName, lastName, email);
        case AuthenticationStatus.Canceled:
            _logger.Info("OpenID: Cancelled at provider.");
            return RedirectToAction("Login");
        case AuthenticationStatus.Failed:
            _logger.Error("OpenID Exception...", response.Exception);
            return RedirectToAction("Login");
    }
    return RedirectToAction("Login");
}

This action method is called twice. The first time by our form being submitted by the user. The second time is a call back (redirect) from the OpenID provider. The first two lines of the method determine which stage we are in. The code inside the ‘if’ statement is executed when the user submits the form. This code creates an OpenID request and redirects to the OpenID provider. Notice that we are requesting first and last names along with an email address. If the user has configured their OpenID provider to share this info it will be available to us.

The OpenID provider then redirects their response back to our action method. This time, there will be a value for the ‘response’ The code inside the ‘switch’ statement processes that response. If the user is authenticated, the username, first & last name and email are send to the following ‘CreateUser’ action method.

private ActionResult CreateUser(string userName, string firstName, string lastName, string email)
{
    User user = _userRepository.FindBy(x => x.UserName == userName);
    if(user==null)
    {
        user = new User
                   {
                       UserName = userName,
                       FirstName = firstName,
                       LastName = lastName,
                       Email = email
                   };
        return View("Create", user);
    }
    Session["UserName"] = userName;
    string fullName = user.FirstName + " " + user.LastName;
    Session["FullName"] = fullName;
    _formsAuth.SignIn(fullName, false);
    return RedirectToAction("Index", "Home");
}

This code checks to see if this user exists in the local database. If the user is not found, the ‘Create’ view is sent to the browser. This gives our application an opportunity to collect and validate the first & last name and email values. I will not show that view because it becomes application specific as to what additional information you collect from each user. I will also not show the action method that the ‘Create’ view posts back to.

If after the OpenID authentication the user was found in the database, the ‘username’ and ‘fullname’ are stored in the ‘Session’ cache, the user is signed in (cookie set) and a final redirect back to the ‘Index’ action method of the ‘Home’ page. This results in showing the panel that provides access to features only available to authenticated users.

The OAuth action methods are shown below. The ‘OAuth’ action method is called when the user submits the form. This uses the DotNetOpenAuth library to redirect (on the Channel.Send method) to the OAuth provider. Notice this code explicitly configures the callback URL.

public ActionResult OAuth(string returnUrl)
{
    var twitter = new WebConsumer(TwitterConsumer.ServiceDescription, TokenManager);
    var callBackUrl = new Uri(Request.Url.Scheme + "://" + Request.Url.Authority + "/Account/OAuthCallback");
    twitter.Channel.Send(twitter.PrepareRequestUserAuthorization(callBackUrl, null, null));

    return RedirectToAction("Login");
}

public ActionResult OAuthCallback()
{
    var twitter = new WebConsumer(TwitterConsumer.ServiceDescription, TokenManager);
    var accessTokenResponse = twitter.ProcessUserAuthorization();
    if(accessTokenResponse!=null)
    {
        string userName = accessTokenResponse.ExtraData["screen_name"];
        return CreateUser(userName, null, null, null);
    }
    _logger.Error("OAuth: No access token response!");
    return RedirectToAction("Login");
}

The OAuth provider then redirects to the specified callback URL (‘OAuthCallback’ in this case) where the response is processed. A similar process is followed as in the OpenID case. Authenticated responses use the ‘CreateUser’ action method (same as for OpenID and shown above).

Summary

Integrating OpenID and OAuth into your application is made very easy by using the DotNetOpenAuth library. There are a number of services popping up that provide a clean implementation of OpenID / OAuth authentication that you can pay to include in your project. The advantage is that they will maintain the compatibility with OpenID / OAuth as it evolves and are able to provide you statistics on access to your site. Otherwise, using the DotNetOpenAuth library and wiring things up your self is not that bad. If you find the DotNetOpenAuth library beneficial and if you feel so inclined to give back, they provide a way to donate on their page.

Did you enjoy this post?

Subscribe, comment, or share...

Comments [1] | Permalink | Save and Share
Saturday, August 07, 2010 10:29:23 PM (Central America Standard Time, UTC-06:00) by rcravens