共用方式為


CCR and Hardware

It has been a while, but that does not mean that the cockpit project has been at a standstill. The first step in terms of hardware was the arrival of an interface board. The card was this one, but I guess it could have been several types of cards. One of the reasons I chose this card was that it has a managed API supplied with it. Again, that probably is also the case with other manufacturer's boards.

So, it arrived. I immediately sat down to look at the managed API that works with this board. The API lends itself easily to use with CCR. Especially, part of it was almost a text book example of the Interleave arbiter. The story is this: When your app starts, you need to start an instance of a manager object. This manager object exposes a couple of events that notify interested parties when interface boards are attached or detached. Each of the interface boards that the manager manages, in turn has their own events when, say, input to the board or output from the board changes. This leads to the following Interleave arbiter groups:

TeardownReceiverGroup failureOrCompletionGroup = new TeardownReceiverGroup(

  Arbiter.Receive<ErrorEventArgs>(false, errorPort, error =>

  {

  // Handle errors

  }),

  Arbiter.Receive<TaskStop>(false, taskStopPort, taskStop =>

  {

  // Handle normal shut down

  }));

ExclusiveReceiverGroup exclusiveGroup = new ExclusiveReceiverGroup(

  Arbiter.Receive<AttachEventArgs>(true, attachPort, attachEventArgs =>

  {

    // Do what is needed to record that the manager has found a board

  }),

  Arbiter.Receive<DetachEventArgs>(true, detachPort, detachEventArgs =>

  {

    // Do what is needed to handle the fact that a board has been detached

  }));

ConcurrentReceiverGroup concurrentGroup = new ConcurrentReceiverGroup(

  Arbiter.Receive<OutputCommand>(true, outputCommandPort, outputCommand =>

  {

  // Set an output port to true...

  }),

  Arbiter.Receive<InputChange>(true, interfaceKitPort, inputChange =>

  {

    // Handle an input change...

  }),

  Arbiter.Receive<OutputChange>(true, interfaceKitPort, outputChange =>

  {

  // If you need to do some processing once the output has changed

  }));

Arbiter.Activate(dispatcherQueue, Arbiter.Interleave(failureOrCompletionGroup, exclusiveGroup, concurrentGroup));

ErrorEventArgs, AttachEventArgs and DetachEventArgs are taken directly from the API of the board producer. TaskStop is just an empty class I created that I can post the port used in the second receiver in the failureOrCompletionGroup. In the exclusiveGroup, what I do is to keep track of the boards that are currently attached. The sweetness is that I can have a dictionary into which I insert entries in the AttachEventArgs receiver and from which I remove entries in the DetachEventArgs receiver totally without having to have synchronization primitives because the exclusive group guarantees exclusiveness from other receivers in the group and from receivers in the concurrent group.

 

The concurrent group is rather straightforward: I have a receiver for OutputCommand instances, which are commands sent by the application when it wants set an output to true. The InputChange receiver handles the case when an input has changed on a board, and the OutputChange receiver handles the feedback that comes back when an output has changed.

 

Finally, all that is left to do is to activate the Interleave arbiter as shown in the last two lines of code.

 

Isn’t CCR just too sweet to not use?