January 2009 Entries

It is the generic brand for multi-threading

In the prior post, I talked about getting the system thread safe.  I didn’t make the methods generic as that would have added in more complexity and I just wanted it to work.

Now as all good coders know, cutting and copying code is the work of vegans and hippies and should be stopped.  So how should we make it reusable rather than a suburb where everything is a slightly tweaked copy of one another.

So lets see how I’d call the Reset method.

I’ll need 3 things

  • The public method
  • The SerialPort DataRecieved event delegate
  • And the worker delegate

public string Reset()
{
	var returnVal = (string)executeComportCall(5, 5000, resetWorker, resetOrFirmwareDataReceived);
	return returnVal;
}

private void resetOrFirmwareDataReceived(object sender, SerialDataReceivedEventArgs e)
{
	var returnVal = comport.ReadLine();

	if (isInvalidResponse(returnVal))
		return;

	comportReturnObject = returnVal;
	comportSingleAccessWait.Set();
}

private void resetWorker()
{
	comport.Write(reset);
}

Pretty easy and straight forward.  Want to add in a new feature, all you need is 3 small functions with no fusing about threading.

But where did that threading code go?

private AutoResetEvent comportSingleAccessWait;
private readonly Mutex comportMutex = new Mutex();
private object comportReturnObject;

private delegate void WorkerDelegate();
private object executeComportCall(int maxRetryTimes, int millisecondsToRetry, WorkerDelegate workerDelegate, SerialDataReceivedEventHandler DataRecievedHandler)
{
	comportMutex.WaitOne();
	comportReturnObject = null;

	comport.DiscardInBuffer();
	comport.DataReceived += DataRecievedHandler;
	comportSingleAccessWait = new AutoResetEvent(false);

	for (var i = 0; i < maxRetryTimes; i++)
	{
		if (comportReturnObject != null)
			break;

		workerDelegate();

		comportSingleAccessWait.WaitOne(millisecondsToRetry);
	}

	comport.DataReceived -= DataRecievedHandler;
	comportMutex.ReleaseMutex();
	return comportReturnObject;
}

private static bool isInvalidResponse(string value)
{
	return string.IsNullOrEmpty(value) ||
		value == returnLine ||
		value == nack;
}

So why do I have a worker delegate when it could be a very simple thing?  For me, I have my OpenRelay method (which I haven’t written yet) that has to add in yet another Auto Reset Event since I have to watch how big of a command I send in.  If I get past the max amount, I have to stop, send in what I have, wait, and then send in the rest when the current is done pouring.

Yes, I do think I’ll have the only thread-safe bartender system.

Thread-Safe bartender

So, I could have done a simple comport.ReadLine() with a while loop and walked away.  As I enjoy over-engineering something that could be done in 5 lines of code, I did it in 50.  But why, why god why did I do it in 40 lines?  To make it thread safe and event driven!

So lets look at the code.

private string _fwVersion;
private readonly Mutex mutex = new Mutex();
private AutoResetEvent firmwareAreState;

public string GetFirmwareVersion()
{
	mutex.WaitOne();
	comport.DataReceived += comport_DataReceivedFirmware; 
	
	_fwVersion = string.Empty;

	firmwareAreState = new AutoResetEvent(false);
	for (var i = 0; i < 5; i++)
	{
		if (!string.IsNullOrEmpty(_fwVersion))
			break;

		comport.Write(firmwareVersion);

		firmwareAreState.WaitOne(500);
	}

	if (string.IsNullOrEmpty(_fwVersion))
		_fwVersion = "ERROR";

	comport.DataReceived -= comport_DataReceivedFirmware;
	mutex.ReleaseMutex();

	return _fwVersion;
}

private void comport_DataReceivedFirmware(object sender, SerialDataReceivedEventArgs e)
{
	var returnVal = comport.ReadLine();

	if (string.IsNullOrEmpty(returnVal) || returnVal == returnLine)
		return;

	_fwVersion = returnVal;
	firmwareAreState.Set();
}

The SerialPort object has the DataReceived event which, in my opinion, is the proper way to handle this type of data transfer.  If I had a while loop, I would either have to Thread.Sleep or just run at 100% until I get the response I want.  Neither of those are appropriate.  We have the tools, we can do this the proper* way.

Lets break down the primary method, GetFirmwareVersion.  The key objects here are the AutoResetEvent and a Mutex which are all in .Net.  This would be easier to explain from the inside out but I’m going to do outside in since people read from the top rather than a random point in the middle.

The Mutex will block the call from being executed before the prior call has finished.  All other calls will be blocked and will wait until the mutex has been released with the ReleaseMutex method.  Then the next queued call will continue execute.  In Clint terms, only one thread can have access at only one time.  This differs from a lock since I can jump functions.

With the AutoResetEvent, I can block the primary thread while I wait for the event to respond to work.  At first, I had this as a WaitHandle and a ThreadPool but realized that this wasn’t needed.  The AutoResetEvent object would then cause a deadlock without the timeout.  Since the relay boards seem not to respond 100% of the time to very prompt calls, I had to be a bit more aggressive to get stuff to work so I added in the for loop and the timeout to verify my command was executed.  Now this is different from a mutex as a mutex stops a new thread from entering to do work while an AutoResetEvent stops the current thread from doing work until it is cleared.

Well, how does one release the block?  Well, in this instance, the DataReceived event from the SerialPort, I call the AutoResetEvent object’s Set method.  I named mine firmwareAreState.  As soon as I call Set, the primary thread is released and continues to do work.  I don’t do pointless while loops and don’t do pointless thread sleeps.  This is similar to a yield instead of a return.

The final key thing that most people don’t do is dynamically add and remove events for an object.  If I fire off this function 5 times and don’t remove the events, I will run into race conditions and memory access issues I don’t want.  I have my function for data access then I remove it as soon as I am done.  On some objects, this may not be a big deal, however my serial port object is global in my object.

So why do this plainly overkill logic for getting the firmware?  This was my test for actually opening the relays.  The logic here will be mirrored but I do think I’ll make it a be more generic so if work does need to be done to tweak it, it is one spot updating rather than cutting and copying 50 spots.  The wonders of delegates and refactoring!

Also, here is my test application UI for the relay boards.  Right now, firmware only works.

image

* By “proper” way, I meant to say that I scratched my head, had a Dr. Pepper and came up with this solution so I could go out and play with my friends.

Wiring Bartender Test

As I’ve stated before, I learned my lessons before about getting everything wired up without properly testing.  So this time around, I’m doing baby steps.  I’m labeling everything like a big boy and making sure everything works before I go to the next fun step rather than build it and then check if everything works properly.

Today I successfully tested the wiring and fired both a 24V solenoid valve and a 12Volt valve at the same time.  Now time to start racking stuff up.

relaySuccessfulTest

Bartender rewiring

I learned a harsh lesson when I had to send a part back with the bartender.  I didn’t have stuff able to be disconnected so literally I had to take the entire system apart to send in the relay boards to get it fixed.

Now everything is designed to be a quick disconnect and able to view where it is.

IMG_5412_2

I still do need a label maker (going to get that tonight) to label all wires.  Board 1 runs 12 volt DC and side 2 will run 24 volt DC.

Giant touch monitor, mmmmm

The St. Louis office got a nice toy for me to play with.  A giant touch capable LCD screen.  I think it can do multi-touch also but not 100% sure as of yet.  I’ll be whipping together some neat proof of concept applications for stuff that would be fun to play with on something so large.

I’m thinking XNA, gravity pits, and comets.  Could do some neat stuff with WPF too!

To test it out, I used my silverlight puzzle I did a bit ago.  I had a rather large sum of people stop at the door and come in and play with it!

PIC-0004 PIC-0005 
* pictures taken with my cell phone, the awesome Samsung Blackjack 2

I have to leave this room else I’ll never get any work done.

drunktender lives!

Much like everyone else, I get distracted and need to clean off my desk from time to time.  In doing so, I discovered my nice little relay circuit board that needed some rewiring after it was tweaked for a small issue that made me pull it.  The old wiring that was used previously was thicker and hard to manipulate.  This made working on the boards hard and more difficult than needed.  On top of that, the wiring was slightly too large for the connections on the boards.  I grabbed some wiring I had from the skateboard instead of strapping 100% of the wiring so now everything should work a lot nicer.  The new wiring is a smaller gauge and is far more flexible.

IMG_2105

This project would be far higher of a priority if I lived in Seattle or Chicago, no doubt.