Tuesday, March 21, 2006

One of the cool aspects of doing Mobile systems is that you often get to do a different kind of programming.  There are plenty of business problems to solve with ASP.NET and SQL but I've recently had a very cool opportunity.

A local company is in the fleet fueling business, this means if you are, say, FedEx in Atlanta, they bring fuel trucks around to your lot at night and re-fuel all your Coca Cola delivery trucks.  The fuel is dispensed using control systems in the truck comprised of fuel meters, printers, and other devices.  As you can imagine with oil-based products being very expensive right now, there are a lot of fraud-prevention mechanisms and business rules related to fuel pricing.  I recently completed, and am now supporting in Production, a new Compact Framework based application that controls the control systems on the truck.  There were many cool-yet-annoying requirements on this effort that forced me to defend-or-change some of my software engineering practices: they system has to talk to several different brands of fuel meters to record gallons, meter totalizers, preset delivery amounts, etc.  Each manufacturer has its own protocol and there are no well published APIs or Web Services: binary hex instead.  We also could not be tied to any specific make/model for any of our other hardware: PDAs, wireless to serial bridges, port replicators, CDMA modems, mobile printers.  Supporting Windows Mobile 2003 and raw CE.NET 4.2 on the same codebase along with 4 different flavors of different OEMs' barcode scanners, cold boot procedures, and WiFi registry settings was also a "Lesson in configurability".

 

Here's a shot of my oh-so-clean and ergonomic development environment with various handheld units:

 

The most excellent part of this system was interacting with the hardware on a real truck once everything was working.  One great thing about being a developer is changing code and then seeing it dance on the screen; pressing a button to calibrate a Fuel Meter, writing exception handling code that tells hardware to reboot itself, scanning a barcode and then watching Low Sulpher Diesel flow out of a real truck at a pre-determined flow rate, now that's fun, and realy damn cool. I recall a conversation with one great architect who was telling me about his experiences with writing warehouse control code many years ago.  He said words to the effect of "Design and testing take on new meaning when a 'bug' results in boxes piling up somewhere or flying off the end of a conveyor belt with nothing there to catch them."  Working in the hardware world occasionally helps make code and the things the code does more real.  If you ever get a chance to work with a hardware system, don't pass it up, you'll probably be thinking and talking about it for a long time.  I'll never forget my first hardware control system experience working for a local manufacturer.  We had a large "test bench" setup so that we could watch lights blink.  One aspect of the software we wrote was the notion of an Alarm that would occur on a client application if hardware operating parameters were outside norms.  The canonical alarm example was that a processor could overheat.  While we stood around deciding how we could accurately test a real alarm situation, one of the testers pried the heatsync off of said processor with a pocketknife to create the alarm state.  Contrast that with the types of testing we normally see on projects, "If I leave this field blank, it doesn't save" and things like that.

Speaking of test benches, here is a shot of some of my test hardware:

All in all, this is one of the coolest projects I've gotten to work on.  I'll ask for permission to post pictures of the actual fuel trucks. Now I just have to convince them to upgrade to CF2 and SQL Mobile...

Tuesday, March 21, 2006 1:44:50 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Tuesday, March 07, 2006

Clemens Vasters has posted an interesting article about O/R mapping.  I can admit that I am one of those people who is drawn to the beauty of an O/R abstraction, and have been since first experimenting with Jasmine and PostgreSQL years ago, and the ideas are obviously much older than that.

After exploring my own O/R implementation I must admit that there are problems with the "aesthetics of the abstraction" as well.  You are seldom working with a fully populated domain model, and lazy loading and the like carries with it its own trade offs.  I'm a bigger fan of Code Generation than pure OR mapping these days.  At any rate, read the article if you are interested in O/R mapping

Tuesday, March 07, 2006 9:42:05 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [2]  |  Trackback
 Thursday, March 02, 2006

I personally feel that a good debugger and ability to debug is one of a programmer's best friends.  This includes debugging onto Windows Mobile devices via ActiveSync.

Recently one of my clients got Windows Mobile 2005 on some devices we ordered.  I set about making sure our application would run properly on it. This application happens to communicate over a wireless network with several different pieces of hardware using various proprietery protocols.  I have gotten used to cradling the device, starting a new debug session in Visual Studio and watching bytes flow back and forth over sockets with the wireless connection.  This new gem we received (A Symbol MC9090 with 625mhz Xscale) insisted on shutting down the wireless card whenever the device was cradled.  This makes it hard to communicate with my hardware, which is seperated from the corporate network and on its own WLAN for very good reasons.  Assuming this was a setting I could change, I contacted their support and got the following disheartening response:

  • Microsoft will not allow us to change this functionality.  In short, they will not allow an AS (Activesync) connection simultaneously with a WLAN connection.
  • Also, please note: This cannot be corrected by a GRIP request (custom product request) or any other mechanism.  At the present time if we change this functionality we will fail Logo Certification and therefore not be able to sell the resulting device.
  • I also found some MSDN articles alluding to Microsoft's claims that "some of their Enterprise customers" had asked for this feature for security reasons.  I have trouble imagining what type of customer asked for this change, but so be it.  It seems ludicrous that this is not a developer-overridable item.  There do look to be some hoops one can jump through (if one is very nimble) to get debugging over WiFi to work on CE5 based devices.  I could also ruin my test environment by putting it on the corporate network, or get cozy with platform bulider and try to make an OS image that does what I want just for testing.

    The developer story for Mobile and Embedded systems could still use some work.

    Thursday, March 02, 2006 11:20:42 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
     Monday, February 20, 2006

    optionsScalper will be giving what is sure to be an interesting presentation on F#.NET at the Wisconsin .NET user's group tomorrow.  optionsScalper has a very serious math background, a scientific mind, and an excellent singing voice.   I like to think of him as someone who's putting the Science back in Computer Science.

    He has piqued my interest in F# so I hope to have it installed and working before the presentation so I can follow along.  I won't attempt to describe F# until I've written some, suffice to say it is a different programming model than the stack-based imperative languages most of us are familiar with and thus presents a paradigm that is much more friendly to certain types of problem solving.

    Monday, February 20, 2006 9:41:10 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
     Monday, February 13, 2006

    I have a small web site I was looking into converting to ASP.NET 2.0 for various reasons *cough resume cough couh* however due to environmental restrictions (corporate politics, not EPA) I have to use MySQL as the data store, and there is an existing schema which is absolutely nothing like the schema the default ASP providers use.  This provided the perfect excuse to dig into some internals and see about providing some Providers. 

    Why would one go through the trouble of implementing these interfaces?  First, as you'll see, its pretty easy.  Second, by doing this you can still use all the great plumbing for role-based security and the "Login" and "User" family of controls that ship with ASP 2.  By looking through my machine.config I can see that I'll need to create and configure instances of two abstract classes: System.Web.Security.MembershipProvider and System.Web.Security.RoleProvider.   There are some intermediate classes you could choose to inherit from like SqlMembershipProvider that might save you some time but in my case it seemed quick enough to start at the base class.  Intellisense and the compiler will tell you what methods you need to override.  For example, MembershipProvider requires an implementation for ValidateUser such as:

    public override bool ValidateUser(string username, string password)
    {
    bool valid = false;
    EmployeeDataAccess dao = new EmployeeDataAccess();
    Employee e = dao.FindByLoginAndPassword(username, password);
    ...

    Simple enough.  If you decide to do this, you may wish to set some breakpoints in methods like RoleProvider.GetRolesForUser and run through your app. 

    public override string[] GetRolesForUser(string username)
    {
    SecurityDataAccess dao = new SecurityDataAccess();
    List<string> roles = dao.GetRolesForUser(username);
    return roles.ToArray();
    }

    In my case there is a small performance hit for running this method.  ASP calls this method to validate your access to pages, proces any LoginView controls trim asp:Menu items if you have securityTrimming enabled, and user code could always call Page.User.IsUserInRole("");   sliding expiration in the ASP.NET cache is a good idea here.  Finally, you just need to tell your web application to use your custom providers.  Supposing my security data store is called "IDMS" and my classes are named accordingly, here are my web.config settings:

    <membership defaultProvider="IDMSMembershipProvider">

    <providers>

    <add name="IDMSMembershipProvider"

    type="IDMSMembershipProvider"

    requiresQuestionAndAnswer="false"/>

    </providers>

    </membership>

    <roleManager enabled="true" defaultProvider="IDMSRoleProvider">

    <providers >

    <clear/>

    <add name="IDMSRoleProvider" type="IDMSRoleProvider" />

    </providers>

    </roleManager>

    So, as you can see, its easy to implement classes to plug into Asp.NET security.

    Monday, February 13, 2006 9:15:14 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
     Thursday, February 09, 2006

    http://www.wi-ineta.org/DesktopDefault.aspx?tabid=89

    A former client called me today to ask if I knew anyone with X,Y,Z skills who was looking for a work.  They weren't interested in consultants at this point so I said I didn't off-hand and directed them to the Wisconsin .NET user's group job board at the above URL.  Note that none of these are entry-level jobs that I can tell.  Employers: you are burning the future to stay warm.  You are assuming someone else will do you the favor of training the recent grad and you can scoop them up when they're no longer green.  Everyone else is making the same assumption and the symptom is kids not going into CS related degree programs.  The result is the President noting in his state of the union address that congress needs to let us import "smart folks" for "Jobs that are having trouble being filled here."

    Thursday, February 09, 2006 12:30:47 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
     Saturday, February 04, 2006

    A lot of developers working with these great modern garbage collected single-inheritance object oriented programming languages on big powerful servers may go their whole career without actually seeing an OutOfMemoryException.  This will happen from time to time on the compact framework and I'm happy to say I typically pay attention to what I'm doing and my hard to track down bug from yesterday is my first OOME.  I have a sync process that merges data into SQL CE 2.  To try to squeeze blood (performance) out of a rock (SQLCE 2.0) it prepares and caches update and insert commands.  Here's a small piece of that code:

    ...            

                System.Data.DataTable schemaTable = dr.GetSchemaTable();

                dbCommand = DataHub.Database.GetCommand(GetUpdateTemplate(ref schemaTable, pk, changeColumn), DataAccessObject.CONNECTION_STRING);
                string columnName;

                SqlCeParameter dbParameter;

                foreach (System.Data.DataRow row in schemaTable.Rows)
                {
                    columnName = (string)row["ColumnName"];
                    int columnSize = (int)row["ColumnSize"];
                    dbParameter = new SqlCeParameter(
                        "@" + columnName,
                        GetSqlDbType(row["ProviderType"].ToString()),
                        columnSize);

                    if (!row.IsNull("NumericPrecision"))
                    {
                        dbParameter.Precision = Convert.ToByte((short)row["NumericPrecision"]);
                    }
                    if (!row.IsNull("NumericScale"))
                    {
                        dbParameter.Scale = Convert.ToByte((short)row["NumericScale"]);
                    }
                    int columnOrdinal = (int)row["ColumnOrdinal"];
                    object pVal = DBNull.Value;
                    try
                    {
                        pVal = dr.GetValue(columnOrdinal);
                        dbParameter.Value = pVal;

    ...

    This worked for a long time until someone decided that a column of type ntext  should be replicated.  The column size for a field of type ntext happens to return something like 580million bytes.   When the code tries to set the parameter value, it finds it can't allocate that much space.  The maximum stack size in the compact framework v1 is 640k (reminds me of MS-DOS low memory, no one will ever need more than 640k); 640kb * 1024b/kb = 655,360bytes, or "not enough" and the OutOfMemoryException is thrown. 

    I feel a little sorry for anyone building a custom sync process using SQL CE.  SQL Mobile is much nicer but does not remove the potential for things like this to happen.  I have a project I'm working on which I'll open-source IF I get it done.  I say if becuase I have occasionally announced some wacky plan here only to be distracted by a shiny object and said project dies on the vine.

    Speaking of stack size optionsScalper was telling me about F# and how .... look, a penny!

    Saturday, February 04, 2006 11:59:35 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [16]  |  Trackback
     Friday, January 27, 2006

    The Few

    The Proud

    The Lucky.

    The Live Messenger Beta Testers.

    Like Scott I managed to get in on the Beta Action for Live Messenger, in my case by signing up on the beta site and waiting for them to send me a download URL.  The folks who know me will tell you I like to chat too much so a new messenger release is a notable event for me.  I like Live Messenger so far, although if you are prone to seizures, dizzyness, or frustration you should turn off the "rollover" feature immediately.  I have yet to try the File Sharing or anything but offline messages. 

    Friday, January 27, 2006 7:20:05 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback