Sunday, November 25, 2012

Adding cheap LCD display and bluetooth shields to a Netduino

I purchased a cheap LCD keypad shield from DX that makes it simple to add a 16x2 LCD display to an Arduino. The board also includes a set of buttons that are connected to a single analog pin through a resistor ladder network.  It's a pretty slick way of minimizing the pin count.  The board is designed for 5V.  The Netduino is a 3.3v system.

The buttons resistor network is wired to the 5V supply so most of the buttons analog values are out of bounds for the 3.3V input.  Others have modified the board to use the 3.3v rail or dropped 5V to 3.3V through a resistor. I didn't do any of this because I don't need the buttons.

The LCD uses digital pins D4-D9 and can operate with 3.3V signals.  The Netduino MF libraries support the on-board devices but not external chips or interfaces.  The LCD Controller is a standard HD44780 which is supported by nice netmftoolbox supplemental library. I downloaded the netmftoolbox library from codeplex and unpacked into a 3rd party directory I keep on my dev machine. I then added two netmftoolbox DLLs to my Visual Studio project using the instructions on the netmftoolbox wiki.

Note the mounting hole offset on the LCD shielddue to the offset headers on the Bluetooth shield.

This program builds on the Bluetooth Shield code from a previous post. It assumes you have connected to the Netduino over Bluetooth Serial and can send commands to the Bluetooth module using something like putty.exe on a Windows machine.  Mac/linux users can use their built in tools.  The program echos anything sent to the LCD and back to the sending machine.  Note that the HD44780 thinks it has a 40 character display no matter what you tell the library so it will fill the display memory for columns 0-39 before wrapping to the next line.  The code supports a couple special characters to move the cursor to the beginning of the first line or the second line so that you don't have to blindly type off screen.

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

///
/// This code is described at http://joe.blog.freemansoft.com
/// Serial code was derived from http://blog.codeblack.nl/post/NetDuino-Getting-Started-with-RS232.aspx
/// 
/// This uses uses netmftoolbox available on codeplex.  It is a pretty slick contributed library.
/// Documentation on how to use it is available at http://netmftoolbox.codeplex.com/
/// http://netmftoolbox.codeplex.com/wikipage?title=How%20to%20use%20the%20classes%3f&referringTitle=Documentation
/// 
/// The Hd44780LCD controller actually has a 40 character wide buffer so we will just write 
/// into the extra space if we write off the edge of the 16character LCD.  So line overflow 
/// doesen't wrap to display boundry. A real program would know what it was writing and where cursor was.
/// 

namespace Netduino_COM2_Echo
{
    public class Program
    {
        static SerialPort serial;
        static Hd44780Lcd display;

        public static void Main()
        {
            initialize_SerialPort();
            initialize_LcdPanel();
            tellUser_WeAreReady();

            // we can toggle the LED including Sleep() because we use an event handler to handle input
            OutputPort led = new OutputPort(Pins.ONBOARD_LED, false);
            while (true)
            {
                led.Write(true);
                Thread.Sleep(250);
                led.Write(false);
                Thread.Sleep(250);
            }
        }

        static void serial_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            // create a single byte array
            byte[] bytes = new byte[1];

            // as long as there is data waiting to be read
            while (serial.BytesToRead > 0)
            {
                // read a single byte
                serial.Read(bytes, 0, bytes.Length);
                // send the same byte back
                serial.Write(bytes, 0, bytes.Length);
                // just some kludgy code to show cursor management
                // there isn't any way to know where the cursor currently is
                if (bytes[0] == 0xd)
                {
                    // lets just use CR to go to the home position
                    display.ChangePosition(0, 0);
                }
                else if (bytes[0] == 0xa)
                {
                    // lets use LF to go to 2nd line home position
                    display.ChangePosition(1, 0);
                }
                else if (bytes[0] == 0xc)
                {
                    display.ClearDisplay();
                }
                else
                {
                    // display on LCD
                    display.Write(bytes);
                }
            }
        }

        static void initialize_SerialPort()
        {
            // initialize the serial port for COM2 (using D2 & D3)
            serial = new SerialPort(SerialPorts.COM2, 9600, Parity.None, 8, StopBits.One);
            // open the serial-port, so we can send & receive data
            serial.Open();
            // add an event-handler for handling incoming data
            serial.DataReceived += new SerialDataReceivedEventHandler(serial_DataReceived);

        }

        /// 
        /// Initialize the display shield
        /// 
        static void initialize_LcdPanel()
        {
            // default width is 16 but controller still acts like 40 char buffer
            // setting the display width won't cause it to wrap at 16 characters
            display= new Hd44780Lcd(
                Data4: Pins.GPIO_PIN_D4,
                Data5: Pins.GPIO_PIN_D5,
                Data6: Pins.GPIO_PIN_D6,
                Data7: Pins.GPIO_PIN_D7,
                RegisterSelectPin: Pins.GPIO_PIN_D8,
                ClockEnablePin: Pins.GPIO_PIN_D9
            );
            display.ClearDisplay();
        }

        /// 
        /// Dumb method that initializes the display in some "friendly way"
        /// 
        static void tellUser_WeAreReady() 
        {
            string greeting = "Type Here To See Text\n\r";
            byte[] greetingBytes = Encoding.UTF8.GetBytes(greeting);
            // Wait a little bet to let the bluetooth connection setup 
            // -- ok this magic worked so I'm keeping it!
            Thread.Sleep(250);
            serial.Write(greetingBytes, 0, greetingBytes.Length);
            display.Write(greeting);
            display.ChangePosition(1, 0);

        }
    }
}

Thanks for reading...

Saturday, November 24, 2012

Using a Cheap Bluetooth Shield on the Netduino

I found this $19 Bluetooth Shield on DX.com from Elec Freaks.  They claim it is Arduino compatible but the Wiki and spec sheet both say 3.3v only, in bold,  which means it doesn't work with a standard 5V Arduino. Netduino boards use Arduino shields and have 3.3V signal levels.

The shield comes with an HC-05 Bluetooth module which can act as either master or slave. You can set the mode by sending it AT style commands after configuring the two switches to set it to command mode.   It is a little simpler than the "you have x seconds from bootup to configure" that some other devices have. My board arrived in Slave Mode which works with a PC acting as Master.

The module has an on-board voltage regulator and a set of daughter card connectors to add additional shields. They used offset top and bottom connectors rather than a single pass through so the card extends off one side.  I'd probably stack this board on top of any other shields I was using.



A basic Netduino comes with two hardware COM ports.  The COM port attached to the USB connector is used for programming and debugging, leaving one available for any purpose.  That means you can't power your Netduino and communicate with it in your program "out of the box" unless you give up debug capability and console output.  The Netduino team does support swapping the two COM ports but it seems like a hassle on the forums. It would be nicer if they supported multiple channels on the USB connector like the TI Launchpad does.  My particular project is unaffected because I intend to power the device over the DC jack and communicate with it over Bluetooth. The USB port will only be used for development.
  • COM1 D0/D1 connected to the USB connector and used for debugging and programming.  Using this in a program means you have no way to control or debug the device.
  • COM2 D2/D3 usually available for an FTDI or other serial breakout board. I jumper'd the Bluetooth shield to COM2.
The unit was simple to pair with my Dell laptop using the pin 1234 as specified on the Wiki.  The Windows 7 Bluetooth stack installed two virtual COM ports, one Outgoing and one Incoming.  I was able to use putty.exe, under windows, to communicate with the device using the Outgoing port.  The Wiki says the Bluetooth shield defaults to 38400.  Mine defaulted to 9600 bps.

I lightly modified a Netduino program provided in this blog that shows you how to do serial communication with a Netduino.  My changes were mainly to use the 2nd COM port and to flash the LED to show that the program is running.

The program sets up communication on COM2 (D2/D3) at 9600 bits per second. It then prints out a welcome message and echos anything you send to the Bluetooth module from your computer over the virtual serial port.

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

namespace Netduino_COM2_Echo
{
    public class Program
    {
        static SerialPort serial;
 
        public static void Main()
        {
            string greeting = "Everything you type in this window will be echoed\n\r";
            byte[] greetingBytes = Encoding.UTF8.GetBytes(greeting);
            // initialize the serial port for COM2 (using D2 & D3)
            serial = new SerialPort(SerialPorts.COM2, 9600, Parity.None, 8, StopBits.One);
            // open the serial-port, so we can send & receive data
            serial.Open();
            // add an event-handler for handling incoming data
            serial.DataReceived += new SerialDataReceivedEventHandler(serial_DataReceived);

            // Wait a little bet to let the bluetooth connection setup 
            // -- ok this magic worked so I'm keeping it!
            Thread.Sleep(250);
            serial.Write(greetingBytes, 0, greetingBytes.Length);

            // we can toggle the LED including Sleep() because we use a multi threaded event handler
            OutputPort led = new OutputPort(Pins.ONBOARD_LED, false);
            while (true)
            {
                led.Write(true);
                Thread.Sleep(250);
                led.Write(false);
                Thread.Sleep(250);
            }

            // original example code said wait forever...
            // Thread.Sleep(Timeout.Infinite);
        }
 
        static void serial_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            // create a single byte array
            byte[] bytes = new byte[1];
 
            // as long as there is data waiting to be read
            while (serial.BytesToRead > 0)
            {
                // read a single byte
                serial.Read(bytes, 0, bytes.Length);
                // send the same byte back
                serial.Write(bytes, 0, bytes.Length);
            }
        } 

    }
}

Thanks for reading...

Monday, November 19, 2012

Installing Oracle Java and Tomcat on Ubuntu Server 12

Ubuntu Server comes with only a command line console so the usual GUI tools are unavailable.  You instead get to Java and Tomcat by hand. Oracle installations require the addition of another apt repository because they are license restricted from the Linux point of view.

Install Java

Enter the following commands into the VMWare visible console.
  1. Ubuntu server doesn't include add-apt-repository so first install that
    sudo apt-get install software-properties-common
    Enter "Y" if prompted.
  2. Add the repository that contains Oracle information
    sudo add-apt-repository ppa:webupd8team/java
    Press "Enter" to continue.
  3. Update the list of available packages
    sudo apt-get update
  4. Install Oracle 7
    sudo apt-get install oracle-java7-installer
    Enter "Y" and click on "<OK>" to accept the license
  5. Verify Java is installed by running
    java -version
You can set the JAVA_HOME for all processes by adding a adding a JAVA_HOME entry in /etc/environment.  You have do this with escalated privileges/sudo. I added this:
    JAVA_HOME=/usr/lib/jvm/java-7-oracle

Install Tomcat

Tomcat requires java so you must have some version installed as shown above.
  1. Install the Tomcat app server using apt-get
    sudo apt-get install tomcat7 tomcat7-admin ufw 
    libtcnative-1
  2. Install the Apache web server using apt-get This is optional for just hacking around in tomcat but is recommended for real production systems.
    sudo apt-get install apache2 libapache2-mod-jk 
  3. And now install the MS SQL Server, MySql and Postgresql java drivers if you are going to want them for your app-server installation
    sudo apt-get install libjtds-java libmysql-java libpg-java 
  4. Groovy is cool so install just because
    sudo apt-get install groovy
  5. Edit /etc/default/tomcat7 and set the JAVA_HOME to /usr/lib/jvm/java-7-oracle

Additional Configuration

Reconfigure the Apache mod-jk plugin that talks to Tomcat if you installed Apache2 in the previous section.
  1. Edit /etc/libapache2-mod-jk/workers.properties
  2. Change workers.tomcat_home to be point to tomcat7 instead of tomcat6
    workers.tomcat_home=/usr/share/tomcat7
  3. Change the default java version to point to the oracle JDK
    workers.java_home=/usr/lib/jvm/java-7-oracle
Restart the servers to pick up the changes

Verify 

  • Restart tomcat7 to pickup the changes
    sudo service tomcat7 restart
  • Verify the services running by hitting the tomcat server on port 8080 with your browser http://<ip>:8080/
  • Restart apache2 if installed
    sudo service apache2 restart
  • Verify the web server is running through the browser by requesting on port 80 http://<ip>
  • Verify they web server and tomcat are wired together using the link below

Credits

I was able to glean useful information on this topic from the following web sites.
  • http://www.ubuntugeek.com/how-to-install-oracle-java-7-in-ubuntu-12-04.html
  • http://magnus-k-karlsson.blogspot.com/2012/04/how-to-set-javahome-environment.html
  • https://wiki.umn.edu/Main/Tomcat7ServerOnUbuntuServer12_04LTS
  • http://thetechnocratnotebook.blogspot.com/2012/05/installing-tomcat-7-and-apache2-with.html

Sunday, November 18, 2012

Virtual Machine Networking: NAT or Bridged?

VMWare and other desktop or embedded hypervisors create virtual networks that the virtual machines connect to when running on the hosting software.  These virtual networks provide network connectivity from the guest machines through the host machine out to the general LAN/WAN.  There are two main modes.

  1. NAT:  The host puts the virtual machines on their own private network and acts as a network gateway for that virtual network.  Guest machines can communicate over the shared network and communicate to the WAN/Internet through the host machine.  Guest machines consume none of the physical network's address space because they are connected on the hosts "virtual network".

    Guest network interfaces can be configured using DHCP, provided by the host, or with fixed IP addresses to simulate a stable server environment.  Fixed IP addresses are handy when the virtual machines need to communicate with each other. VMWare typically uses the host network's VMnet8 VLAN which doesn't change network range across reboots.

    This mode works well where the guest machines only need outbound access to the global network.  It is also useful where the host machine is mobile and plugs into multiple other physical networks.  No guest reconfiguration is necessary when the host is connected to a new network.
  2. Bridged: The host essentially creates a new IP adapter for each virtual machine and bridges the virtual network adapters to the physical network.  Guest machines consume address space on the physical network. A host running 2 virtual machines with Bridged networking has 3 IP addresses on the main network. It has one for the host and one for each virtual machine.

    Guest interfaces can be configured using DHCP provided by the network or with fixed IP addresses. Fixed IP addresses make it easier to route requests to the VMs.

    This method is the best method to use if the guest / virtual machines accept inbound traffic from the greater LAN/WAN or Internet. This mode works well if the capacity to allocate to the additional IP addresses.

Oracle has a good explanation of NAT and Bridged in VirtualBox at https://blogs.oracle.com/fatbloke/entry/networking_in_virtualbox1
VMWare has a good NAT explanation in their virtual networking environment http://www.vmware.com/support/ws45/doc/network_nat_details_ws.html

Setting the Size of the Terminal / Console Window in a Linux Server VM

We did a lot of Linux virtual machine installs when I worked with VMWare's SpringSource group. It let us run multi-node clusters off our MacBooks for customer demos.  We usually used desktop installes because they have you multi-terminal access to the machines.  I decided I wanted get some of my Linux/Java/OpenSource mojo back after 8 months on a Microsoft only project.  I downloaded Ubuntu 12.10 and installed server version so I could spin up more VMs on my Dell.

The server install is thin and the Linux console defaults to 640x48 as displayed in the VMWare Player/Workstation.  It wasn't exactly obvious how to make that terminal window larger.  The desktop version of Ubuntu is sync'd with the VMWare window size through the VMWare tools.  That isn't true of the server version.  You have to do the following steps. These assume you have created and installed a new machine and are logged into the console window on the Virtual Machine. I did this with Ubuntu 12.10 Server.

  1. First determine the resolution you wish to have the console run at. Most cards support the standard VESA resolutions and their associated mode numbers.  Pick the resolution you want and remember it's mode number.  I wanted 1024x768x16 so my mode number is 791. Additional information on how this works in ubuntu is available at the Ubuntu help site.
  2. Type sudo su at the terminal prompt and enter your password. This leaves you with a root capable shell.  You're more secure if you just run the su command for each command prompt because you won't do anything dangerous by accident but I'm kind of lazy and elevate my privileges.
  3. Edit /etc/default/grub with something like
        vi /etc/default/grub
  4. Find the line with GRUB_CMDLINE_LINUX_DEFAULT and add vga=xxx where xxx is the mode number.  It should look something like:
        GRUB_CMDLINE_LINUX_DEFAUT="quiet vga=791"
    1. You will see other documentation that talks about modeset or nomodeset. I think those are more applicable when you are not running on a virtual machine and where there are custom settings for a particular video card.
    2. Other document says you change the resolution using the line that includes GRUB_GFXMODE by removing the '#' at the beginning and setting the resolution to the same as the VESA mode. That didn't work for me and was unnecessary when I made the change just discussed.
  5. Save the changes and exit the editor
  6. Update grub with the new settings.  The settings will not take affect with out this.
        update-grub
  7. Restart your machine with the
        reboot command if you are still elevated or
        su reboot
    if not.
Ubuntu server takes up 1.2GB on the disk with additional services or tools installed.  It makes a nice lightweight virtualization platform.

Changing the Login Prompt in Linux

I try and standardize my user ids and passwords on my development virtual machines but sometimes a piece of software has tighter restrictions.  In that case I change the Linux login message to tell me the default user ids and passwords.  The contents of /etc/issue are displayed before the login prompt. Edit /etc/issue and add your user id and password information.  DO NOT do this for any system that is accessible to the Internet or that contains real or sensitive data.