Sunday, April 12, 2015

C# IOIO and I2C devices

The IOIO C# library on GitHub now has basic I2C support.  Protocol support and resource management is lifted from the Java library.  The upper API is message based rather than object based. TWI/I2C/SPI is managed via outbound messages. Data from I2C devices and message acknowledgements from the IOIO come back asynchronously via inbound Messages.


Hardware

This was tested with an IOIO V1, Bluetooth module, a JeeLabs Expander Plug and an old Computer power LED.  

I2C device


The Expander Plug is based on the MicroChip MCP23008 port expander.  Programming examples are available on the Jee Labs web site. The Microchip web site has the chip programming guide.

The LED assembly already had a current limiting resistor. I just plugged it in across the "+" pin on the expansion port and the port pin next to the power pin.

The port expander default address is 0x20.  It has 10 registers that control behavior and transfer data.

JeeLabs makes a bunch of 3.3v I2C devices that are easy to use.




IOIO Hardware

You must have pull up resistors on DA and CL.  I wasted 3 hours convinced that I didn't really need the resistors. You can see my 10K Ohm pull resistors tied to the back side of a 3.3v power pin.  Each resistor is tied to its pin and the 3.3v power pin. It is not a parallel resistor even if it looks like that in the picture.

JeeLabs has their own pin naming convention. AIO corresponds to IOIO I2C CLK pin.  DIO corresponds to IOIO I2C pin Data

Connect up 4 wires on the device
  • Expander DIO -> IOIO I2C Data
  • Expander AIO -> IOIO I2C Clock
  • Expander +   -> IOIO +3V
  • Expander GND -> IOIO GND
  • Expander INT -> N/C
  • Expander Pwr -> N/C
For TWI 0
  • Expander DIO -> IOIO Pin 4 (DA0)
  • Expander AIO -> IOIO Pin 5 (CL0)
  • Expander +   -> IOIO +3V
  • Expander GND -> IOIO GND
  • Expander INT -> N/C
  • Expander Pwr -> N/C

Talking with the Port Expander

The TwiI2CTest.cs in the GitHub project shows more details as to how this is set up. The test logs messages from the IOIO.  It does not show how to pick up the return messages using notifications.

Open and Configure TWI

We get two responses back when we configure one of the Twi pin sets.  I don't yet understand why the TXStatus report says 256 bytes remaining when it is actually 0.  

This code posts the TWI configuration message. This code:
int TwiVirtualDevice = 0;
 LOG.Debug("Configuring TWI");
IOIOMessageCommandFactory factory = new IOIOMessageCommandFactory();
ITwiMasterConfigureCommand startCommand = factory.CreateTwiConfigure(TwiVirtualDevice, TwiMasterRate.RATE_400KHz, false);
ourImpl.PostMessage(startCommand);
System.Threading.Thread.Sleep(50);
TwiSpec twiDef = startCommand.TwiDef;
results in this output
TwiI2CTest             - Configuring TWI
IOIOImpl               - Post: IOIOLib.MessageTo.Impl.TwiMasterConfigureCommand
IOIOHandlerCaptureLog  - HandleI2cOpen i2cNum:0
IOIOHandlerCaptureLog  - HandleI2cReportTxStatus i2cNum:0 bytesRemaining:256

logging truncated to improve readability.


Configure port expander I/O pins as outputs

Set a value in the registers to configure the pins as outputs.  We get a confirmation message

This code:
int JeeExpanderAddress = 0x20;
byte RegisterIoDir = 0x00;
byte[] ConfigureAllOutput = new Byte[] { RegisterIoDir, 0x00 };
LOG.Debug("Configuring port direction as all output ");
ITwiMasterSendDataCommand configureDirectionCommand = factory.CreateTwiSendData(twiDef, JeeExpanderAddress, false, ConfigureAllOutput, 0);
ourImpl.PostMessage(configureDirectionCommand);
System.Threading.Thread.Sleep(50);
results in this output:
TwiI2CTest             - Configuring port direction as all output 
IOIOImpl               - Post: IOIOLib.MessageTo.Impl.TwiMasterSendDataCommandTwi:0 ExpectBack:0 SendingBytes:00 00
IOIOHandlerCaptureLog  - HandleI2cResult i2cNum:0 NumBytes:0 ReceivedBytes:

logging truncated to improve readability.

Set the port expander output pins to"low" values

Note: The LED lights up when the pins sink current. This means the LED lights up when the pins are low.

This code writes to a control register and then queries the output latches for state.
LOG.Debug("Post Low");
ourImpl.PostMessage(commandLow);
System.Threading.Thread.Sleep(150);
LOG.Debug("Check Are Latches Low");
ourImpl.PostMessage(queryOLat);
System.Threading.Thread.Sleep(50);
results in this output
TwiI2CTest             - Post Low
IOIOImpl               - Post: IOIOLib.MessageTo.Impl.TwiMasterSendDataCommandTwi:0 ExpectBack:0 SendingBytes:09 00
IOIOHandlerCaptureLog  - HandleI2cResult i2cNum:0 NumBytes:0 ReceivedBytes:
TwiI2CTest             - Check Are Latches Low
IOIOImpl               - Post: IOIOLib.MessageTo.Impl.TwiMasterSendDataCommandTwi:0 ExpectBack:1 SendingBytes:0A
IOIOHandlerCaptureLog  - HandleI2cResult i2cNum:0 NumBytes:1 ReceivedBytes:00

logging truncated to improve readability.

Set the output pins to"high" values

Write the pin output control registered. Write  bits to the register whose values represent pin state
LOG.Debug("Post High");
ourImpl.PostMessage(commandHigh);
System.Threading.Thread.Sleep(150);
LOG.Debug("Check Are Latches High");
ourImpl.PostMessage(queryOLat);
System.Threading.Thread.Sleep(50);
results in this ouiput
TwiI2CTest             - Post High
IOIOImpl               - Post: IOIOLib.MessageTo.Impl.TwiMasterSendDataCommandTwi:0 ExpectBack:0 SendingBytes:09 FF
IOIOHandlerCaptureLog  - HandleI2cResult i2cNum:0 NumBytes:0 ReceivedBytes:
TwiI2CTest             - Check Are Latches High
IOIOImpl               - Post: IOIOLib.MessageTo.Impl.TwiMasterSendDataCommandTwi:0 ExpectBack:1 SendingBytes:0A
IOIOHandlerCaptureLog  - HandleI2cResult i2cNum:0 NumBytes:1 ReceivedBytes:FF

logging truncated to improve readability.

Close the TWI interface

Remeber to clean up after yourself. This releases Twi pool
ITwiMasterCloseCommand closeCommand = factory.CreateTwiClose(twiDef);
ourImpl.PostMessage(closeCommand);
results in
IOIOImpl               - Post: IOIOLib.MessageTo.Impl.TwiMasterCloseCommand
IOIOHandlerCaptureLog  - HandleI2cClose i2cNum:0

logging truncated to improve readability.

Conclusion

Sometimes your first impressions are correct

Sometimes you run across interesting outfits when interviewing or working with other organizations.

You know you should slide away from an opportunity when...


You think in the interview:
"If these guys were an airline..."
"The countryside would be littered with flaming wreckage."
An interviewer describes their new approach and conversation goes something like:
Interviewer: We're moving more of our software development off shore.
You: That doesn't improve success rate if you don't change the way you do other things.
Interviewer: Yes, but our failures will cost less

They may not be as Agile as they think they are when


They describe their agile SCRUM process:
"They have one 3 month sprint per release"
"They made the managers the SCRUM managers since they assign work anyway" 

It may not be the technical opportunity they described...


The senior architect interview includes:
Writing Tower of Hanoi pseudo code in front of 1/2 a dozen people while they critique your algorithm.
The company talks about how big their projects are when:
Their automated builds take under 5 minutes.

I have been lucky with my customers and employers.  

Monday, April 6, 2015

Controlling a Servo attached to an IOIO from Windows WPF application

The IOIO C# library on GitHub now includes a very basic Windows WPF application that lets you control a Servo with your mouse.

The program assumes your IOIO is attached to your PC via Bluetooth and that you have a servo on Pin 3.

Run the program from inside Visual Studio. Step through the disconnect exception if you run this with debugging enabled.

Backup the drivers when installing Windows 10 on a Winbook TW100

Yes, you can install Windows 10 on a Winbook TW100 or other BayTrail tablet.  There are postings on the Microcenter support web site where folks describe how to to this on other WinBook tablets like the tw700. I have only a couple minor things to add.
  1. The tablet has a 64 bit processor and a 32 bit BIOS/EFI.  Use the 32 bit Windows 10 ISO available from Microsoft. Windows 10 32 bit ISOs became available in January 2015. It only has 2GB of memory so a 32 bit OS is fine. I installed the enterprise version.  The standard version didn't work for me but it was probably pilot error
  2. Build a restore medea or backup the TW100 driver directory using one of the available tools. It would be best to build a restore media instead of backing up the drivers. This would let you go back to Windows 8.  I was unable to do this with any of my flash drives. I instead used a tool off of sourceforge to back up the drivers. I now Windows 10+ forever.
  3. Make a copy of TouchSettings.gt in C:\Windows\inf.  Driver tools will not backup this file. This file is critical to getting the digitizer to work.
  4. Create a bootable flash image using the ISO Rufus based the guidance in the forums.
  5. Install Windows 10 per the forum instructions.
  6. Use Device Manager control panel to Update missing device drivers from your backup.
  7. Restart (again).
This zip file includes TouchSettings.gt and should include drivers you need.

Notes:

  • The tablet will ask for the three finger salute or a power+win-key press to unlock the device if it has gone to sleep when plugged in. I've never been able to get any combination to work in this situation and often just reboot.
    1. There is only one power plan "Balanced" with the March 2015 Windows 10 pre-release build.  The battery only lasts a day with this plan.
    2. I've turned off screen locker by changing one of the Interactive Login group policies. This makes the device act like a normal tablet and lets avoid the ctrl-alt-del screen

    Thursday, April 2, 2015

    Message Routing using Double Dispatch with C#

    This post describes message routing inside an application. It does not describe message routing across message brokers or across systems.

    Message driven, or push based notification, systems stream Messages from message sources to interested parties (Observers).  There are often multiple message types routed to multiple observers.  Message types are represented in code as Message interfaces/classes.

    Message Observers are often interested in some subset of the messages and implement some type of interface or registration scheme that tells the message routing module which message types they are interested in.

    Scenarios

    One use case for this is a User Interface that streams UI events (Messages) from various components to event handlers (Observers).  The message sources create messages specific to that event type. The event handlers may receive and process messages of one or more types.

    Another use case might be some type of IoT device like an IOIO that creates events at scheduled intervals or based on some type of external input. Each change event has its own message type.  Components that have interest in some subset of the messages can subscribe for notifications of those types of messages/events.  The dispatcher notifies the interested subscribers every time messages of the correct type appear.

    Complexity

    We want to take messages of various types and route them to handlers without losing the typing information and without resorting to casting in the handlers . This means we'd like to bind message types to some kind of Observer Notify() method that accepts that exact message type or the next closest abstract version.  This is similar to the MVC or other models where inbound web requests are routed to controller methods that have a signature that matches the inbound object type as closely as possible.   

    Message subscribes should be simple with any dispatch complexity hidden in the messages or dispatcher.  We'd like to make it easy to add additional message types and support their associated observers.  This means we want to avoid large God classes with giant case statements that identify messages by types and route based on specific message signatures. 

    Dynamic Dispatch and Double Dispatch

    Double dispatch pushes message type to observer method binding out of the core dispatch (or receiver) to the messages themselves. It is similar to a Visitor pattern.


    1. Observers register interest with the message receiver. Observers implement Observer() methods based on the message types they are interested. Dynamic dispatch will determine if an observer is interested in a specific message type at runtime. An observer can be interested in more than one message type.  
      1. I'll use the Microsoft Observer methods here.  Ex: OnNext(GameStart), OnNext(GameEnd). You could use other interfaces like Visit or Dispatch.
    2. A message is generated and posted to a message queue.
    3. The message dispatcher receives the message. The receiver may be listening on some message stream or queue.
    4. The dispatcher iterates across each observer.
      1. Each observer is Dispatched to Message.
      2. The message calls the Observer's  OnNext() method that is most closely typed to the message type.


    Implementation Example

    Message Types

    The Interface diagram to the right shows the Business message hierarchy. No special API or behavior is specified here.

    All message interfaces are subclassed off.  All the IMessage types other than IMessageBase are implemented by concrete classes.
    IMessageNotification isn't shown here. It is a notification support interface used as part of the double dispatch process.

    Concrete message classes implement two interfaces

    1. he business interface that contains the message properties and any special behavior.
    2. The message notification interface used for observer dispatch.   The dispatcher/router invokes the IMessageNotification interface one time for each registered observer.


    Observers

    Observers implement two interfaces, a non-genericized IObserver  and a genericized IObserver<MessageType> that expresses interest in a specific message type or its sub types. IObserver is a marker interface.  IObserver<MessageType> is the dynamic dispatch interface. Observers implement the IObserver<MessageType> interface one time for each message type they are interested in.

    Observers register for notification using the Subscribe(IObserver) method modeled on IObservable. They do not register which message types they are interested in. This will be determined at runtime by the Message's dynamic dispatch code.



    Dispatch Mechanics

    The dispatcher/message receiver receives messages as they come in. It invokes the message's  Dispatch(IObserver) one time for each observer.  The Dispatch(IObserver) method tries to find a IObserver<MessageType>  method on the Observer that can receive this message type. It then calls Dispatch<IObserver, MessageType) on itself.  That method then invokes  OnNext<MessageType> on the Observer.  It invokes the OnNext<MessageType> for the message type that is closest to the the type of the message doing the processing. 

    Example Code


    ...begin source code... ...end source code...

    Notes

    Some of the pattern in here came from this stack overflow posting
    Wikipedia has good descriptions of Multiple Dispatch and Double Dispatch

    This is one of the core patterns in Smalltalk. I'm just saying this so Smalltalker's don't flood me with email telling me how they've been doing this since the 80s.

    This post created 4/2015