Silverlight 5 Released
Saturday, December 10th, 2011Just read that Silverlight 5 has just been released. Off to the downloads page and some replanning of this weekends activities.
For more information visit the Silverlight home page.
Just read that Silverlight 5 has just been released. Off to the downloads page and some replanning of this weekends activities.
For more information visit the Silverlight home page.
In a previous post I mentioned that replacing a single LED in the centre of a matric would be murder and so it will be. The matrix I have in mind is an 8 x 8 x 8 LED cube controlled by a Netduino board. Now it should be obvious that there are not enough pins to connect 512 LEDs to the Netduino without some magic being involved. This is where the Persistence of Vision post comes into the picture. In theory, it should be possible to control an array using a group of shift registers and a multiplexer circuit. So for the next few weeks this is what I’ll be looking at.
The previous post on Persistence of Vision had a simple while loop which allowed 16 LEDs to be controlled from the main program loop. In the final program this will be too cumbersome and timing is almost certainly to become an issue. To overcome this we will need to have the display logic separated from the control logic. This will allow the display to be continuously updated whilst the main program loop is working out what should be displayed next. The following tests this concept by turning on on LED at a time in a bank of 8. If this project has a chance of working then the 8 LEDs should all appear to be switched on permanently.
The hardware is relatively simple. We have one shift register connected to the Netduino. This is in turn connected to 8 LEDs through current limiting resistors. The schematic looks something like this:
The software requires us to take the display logic from previous posts and add this to a new class. This class will need to have a method executing in it’s own thread in order to allow the main program and the display driver to run at the same time. So splitting the display code into it’s own class we get something like this:
class LEDCube
{
/// <summary>
/// SPI bus to use to send data to the shift registers.
/// </summary>
SPI spi = null;
/// <summary>
/// CSPI bus configuration
/// </summary>
SPI.Configuration config;
/// <summary>
/// Buffer holding the display data.
/// </summary>
private byte[] buffer;
/// <summary>
/// Constructor for the LEDCube class.
/// </summary>
public LEDCube()
{
config = new SPI.Configuration(SPI_mod: SPI.SPI_module.SPI1,
ChipSelect_Port: Pins.GPIO_PIN_D9,
ChipSelect_ActiveState: false,
ChipSelect_SetupTime: 0,
ChipSelect_HoldTime: 0,
Clock_IdleState: true,
Clock_Edge: true,
Clock_RateKHz: 400);
spi = new SPI(config);
buffer = new byte[1];
buffer[0] = 0;
}
/// <summary>
/// Main loop which continuously updates the display from the buffer.
/// </summary>
public void DisplayBuffer()
{
while (true)
{
lock (buffer)
{
spi.Write(buffer);
}
}
}
/// <summary>
/// Change the byte in the display buffer.
/// </summary>
/// <param name="b">Byte to put into the buffer.</param>
public void UpdateBuffer(byte b)
{
lock (buffer)
{
buffer[0] = b;
}
}
}
Much of the code should be familiar, we have the SPI bus and config variables along with a constructor to make a new instance of the SPI bus. The new code is really the DisplayBuffer and the UpdateBuffer methods.
Note that both of these methods use locking to ensure that the methods are thread safe.
The main program loop now looks something like this:
LEDCube cube = new LEDCube();
Thread display = new Thread(new ThreadStart(cube.DisplayBuffer));
display.Start();
while (true)
{
byte value = 1;
for (int index = 0; index < 8; index++)
{
cube.UpdateBuffer(value);
value <<= 1;
}
}
A new LEDCube is created and at first this is not running in it’s own thread. The next two lines create and start a new thread. The thread is executing the DisplayBuffer method. We then start the main program lopp which simply sets each bit in a byte and the updates the buffer in the cube using UpdateBuffer.
Next step, build the control logic for 512 LEDs.
Following the post earlier this week regarding the implementation of a ShiftRegister class which allows the Netduino to control a series of 74HC595 shift registers I had a look at what would be needed to make the system count and show the output in binary on a series of LEDs. What you see here is the result. The hardware is the same as the previous post, only the software has changed.
One of the main desires is to allow the programmer to use the natural language features of C# to work with this class. The modifications should therefore support operations such as assignment, logical and etc. The main program loop for a counter should look something like this:
ShiftRegister shiftRegister = new ShiftRegister(16, Pins.GPIO_PIN_D9);
for (ushort index = 0; index < 10000; index++)
{
shiftRegister = index;
Debug.Print("Count: " + index + ", " + shiftRegister.ToString());
shiftRegister.LatchData();
Thread.Sleep(100);
}
In order to support this we will need to overload the implicit assignment operator for an unsigned short being assigned to a ShiftRegister instance. This results in the following code:
/// <summary>
/// Overload the assignment operator.
/// </summary>
/// <param name="usi">Unsigned short integer to assign to the register.</param>
/// <returns>New ShiftRegister holding the unsigned short value.</returns>
public static implicit operator ShiftRegister(ushort usi)
{
ShiftRegister result = new ShiftRegister(16); // ushorts are 16 bits.
ushort mask = 1;
for (int index = 0; index < 16; index++)
{
result._bits[index] = (usi & mask) > 0;
mask <<= 1;
}
return (result);
}
This generates some problems with the base shift register class from the last post. Most noteably the creation of the SPI instance. The run-time system will generate an error should the programmer try and create two objects wanting to access the SPI bus. Reading the above code you can see that the assignment overload requires a new ShiftRegister instance to be created. A few changes are therefore required in order to allow the system to share the same interface. In order to allow this, the base class moves the SPI object from a shared instance to a static object. This ensures that only one of these can exist at any time. The remaining modifications to the class support this change and add a ToString() method for debugging. The modified code and a sample test project can be found here and the following video shows the application in action.
The base functionality assumed that the class is the only class wanting to use the SPI bus. The number of chips and breakout boards using is large and so it is likely that the programmer will want to communicate with several slave devices using the same bus. This is allowed using the SPI protocol and for the moment this is left as an exercise for the reader.
Looks like Microsoft have released the beta of Silverlight 5. Details of the new features can be found here.
Debugging data binding ! Finally 🙂
A while ago I wrote about my renewed relationship with the NE555 when I produced a simple astable circuit. The experience of trying to work out the values lead me to think about writing a calculator application. This lead me to wonder how I could validate the results given that I do not have an oscilloscope – simple add a data logger to the Netduino and use that. The following shows how I did it and provides some information about how the code works.
Write application which provides the functionality:
This will require two applications, one to interact with the user and perform the calculations and data plotting and one application to capture the data on the Netduino.
This application is an extension to the Silverlight application which I documented here. This has the core functionality required to allow the Netduino Plus to communicate with a Silverlight application. A few slight changes were required, namely:
For the first of the changes we simply need to add some additional variables to store the configuration and modify the ProcessCommand method. The system uses the Command.html special file (as before) to receive commands/requests from the user. The valid actions implemented are as follows:
Action | Parameters | Description |
t | Test the connection. This simply returns a Hello string to the calling application. | |
g | Get the preconfigured file and send this back to the caller. | |
c | SampleRate and FileName | Configure the Netduino data logger. The system will configure the Netduino to log data every SampleRate milliseconds and store the results in the specified file. |
The last part of the change to the web server is to provide a mechanism to communicate the change to the data logging component. This done using an event as the data logger and the web server are executing in different threads.
The next change required is to implement the data logging functionality. The data logging runs in the main thread. The on board switch was used to trigger data collection rather than having the Netduino log data permanently. The on board LED was also used to indicate if the board is collecting data. A Timer was used to trigger the collection of data from the analog pin. This meant that the board can capture at most 1000 samples per second.
private static void onBoardButton_OnInterrupt(uint data1, uint data2, DateTime time)
{
if (data2 == 0)
{
if (_logging)
{
_timer = null;
_onBoardLED.Write(false);
_logging = false;
}
else
{
using (TextWriter tw = new StreamWriter(@"SD" + _fileName, false))
{
tw.WriteLine("Ticks,Data");
tw.Close();
}
_startTime = Utility.GetMachineTime().Ticks;
_timer = new Timer(new TimerCallback(CollectData), null, 0, _sampleRate);
_onBoardLED.Write(true);
_logging = true;
}
}
}
This code is tied to the on board switches interrupt. It starts and stops the logging depending upon the current state. A logging start request opens the specified file and puts the header into the file. This effectively deletes and results already stored in the file. The timer is created and tied to the CollectData callback. This callback simply reads the pin and writes the number of ticks since the start of the logging session along with the reading from the pin.
private static void CollectData(object o)
{
string data;
data = Utility.GetMachineTime().Ticks - _startTime + "," + _analogInput.Read();
using (TextWriter tw = new StreamWriter(@"SD" + _fileName, true))
{
tw.WriteLine(data);
tw.Close();
}
}
This is where the project began to take on a life of it’s own. The code discussed here consumed the majority of the time spent on the project. The code is fairly well commented and so the main features will be discussed here.
The project uses MVVM to implement a calculator for the NE555. This results in little code in the code behind for the main page. What code there is simply creates a new instance of the View Model class and calls methods in the class when buttons on the interface are clicked. The remaining communication is achieved using data binding in Silverlight.
The calculator can be used to calculate one of the following (given the remaining three values):
The system takes three of the specified values and calculates the remaining. The values for the components can come from three sources, a standard component, a user specified value or a range of values.
If single component values are used (either standard components or user values) then a single result set is generated. If a range of values are selected for one or more of the components then the system will generate a table of values with one line for each of the requested values.
So much for discussing the application, it is probably just as easy to try the application which can be found here.
The first tab (Parameters on the application collects the parameters for the calculations and allows the user to request that the results are calculated.
The next tab (Results) presents the results of the calculation.
The final tab (Netduino) allows the application to communicate with a Netduino Plus.
Although the Silverlight application is hosted on my web site, you can still use this to communicate with your Netduino Plus if it is connected to your network.
The resulting application is more or less complete. There are a few things which could be done to make it more robust or more useful, namely:
These are left as an exercise for the reader.
The source files for this project can be found here:
Astable NE555 Silverlight Calculator
As usual, these sources are provided as is and without warranty. They are used at your own risk.
The Silverlight application can be run from a web site or from Visual Studio. The web server needs a little more than just running the project on the Netduino. You will also have to place the clientaccess.xml policy file on the SD card as Silverlight requests this file in order to determine if it allowed to talk to the web server.
Having been working with the Netduino Plus for a few week I wanted to look at the possibility of using the network to communicate with the board. Having browsed the forums on the Netduino home page I found a few discussions about using this board as a web server including using a WiFly board to hook up to a wireless network. The SDK also comes with several examples of network programming with the micro framework.
Allow the PC to send and receive data to the Netduino Plus over a wired network.
The Netduino Plus board does not have the same resources available to the programmer you would normally find in a PC environment. This leaves the programmer with little to work with. The HTTP server supplied as a sample with the micro framework occupies a substantial amount of memory on the board.
One of the simpler examples provided with the framework implements a very simple server. A little bit of redesign and coding converted this into a very basic web server. The server is capable of serving a few file types (HTML, JPG, CSS, Javascript and XAP) to the client.
The main program is a simple affair. It contains a few definitions to support the file locations for the web files along with a small amount of code to offer “I am alive” feedback to the user.
For the “I am alive” feedback I have chosen to use the on board LED and button. The LED will flash twice when the user presses the on board button. A small power saving I know.
The final job of the main program is to instantiate the web server. This will start the server listening on the specified port.
private static OutputPort _onBoardLED;
private static InterruptPort _onBoardButton;
public static void Main()
{
_onBoardLED = new OutputPort(Pins.ONBOARD_LED, false);
_onBoardButton = new InterruptPort(Pins.ONBOARD_SW1, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeBoth);
_onBoardButton.OnInterrupt += new NativeEventHandler(onBoardButton_OnInterrupt);
_webServer = new WebServer(WEB_ROOT, WebServer.HTTP_PORT);
Thread.Sleep(Timeout.Infinite);
}
///
/// Flash the on board LED to let the user know we are still alive.
///
private static void onBoardButton_OnInterrupt(uint data1, uint data2, DateTime time)
{
if (data2 == 0)
{
_onBoardLED.Write(true);
Thread.Sleep(250);
_onBoardLED.Write(false);
Thread.Sleep(250);
_onBoardLED.Write(true);
Thread.Sleep(250);
_onBoardLED.Write(false);
}
}
The code for this can be found in SimpleWebServer.zip.
The files served provides a static web site to the client (a trip back to the 1990s).
The web server class contains the methods to create a non blocking web server which will listen to the network on the specified socket and process the requests.
The constructor for the class sets up the local variables and creates a new thread to listen for requests:
public WebServer(string webFilesLocation, int portNumber)
{
_webRoot = webFilesLocation;
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_socket.Bind(new IPEndPoint(IPAddress.Any, portNumber));
_socket.Listen(int.MaxValue);
new Thread(Listen).Start();
}
The Listen method does the main work of listening to the socket, getting the request and converting it to a string which can be processed and finally closing the socket.
private void Listen()
{
while (true)
{
using (Socket client = _socket.Accept())
{
int requestSize;
byte[] buffer;
int amountRead;
string request;
requestSize = client.Available;
buffer = new byte[RECEIVE_BUFFER_SIZE];
Debug.Print("Request received from " + client.RemoteEndPoint.ToString() + " at " + DateTime.Now.ToString("dd MMM yyyy HH:mm:ss"));
amountRead = client.Receive(buffer, RECEIVE_BUFFER_SIZE, SocketFlags.None);
request = new string(Encoding.UTF8.GetChars(buffer));
Debug.Print(request);
ProcessRequest(client, request);
buffer = null;
request = null;
client.Close();
}
}
}
The method which processes the request is a simple method which is designed to check the first list of the request and verify that the web server can understand the protocol of the request. This server can only process HTTP 1.1 get requests. The first line of such a request should come through as something like the following:
GET filename.html HTTP/1.1
The ProcessRequest method looks something like the the following:
private void ProcessRequest(Socket client, string request)
{
string[] firstLine;
firstLine = request.Substring(0, request.IndexOf('n')).Split(' ');
if (firstLine[0].ToLower() != "get")
{
Send(client, HTTP_501_NOT_IMPLEMENTED);
}
else
{
if (firstLine[2].ToLower() != "http/1.1r")
{
Send(client, HTTP_505_HTTP_VERSION_NOT_SUPPORTED);
}
else
{
SendFile(client, firstLine[1]);
}
}
}
The constants in upper case contain response strings indicating that the web server has encountered an error.
The key work for sending the files and processing commands can be found in the SendFile method. The first thing this method does is to check on the file name to see if it is the “special command” file. If it is then the query string is passed to the command processor. All other requests are processed as request for files which should exist on the server. The system works out if it understands the file type and if it does then the file is sent to the client.
One design decision taken was to restrict the output to the client to 256 byte chunks. This decision was made in order to conserve memory.
The eventual aim is to connect sensors etc. to the Netduino and then read the data from them over the network. In order to test the theory a “dummy” sensor was added to the command processor. This simply returned the number of milliseconds from the current time divided by 100.
TimeSpan time;
tme = Utility.GetMachineTime();
Send(client, "Time " + time.Hours + ":" + time.Minutes + ":" + time.Seconds);
By using the command.html file and the QueryString we can test the system by making a simple request from the web browser. For instance:
http://192.168.10.100/Command.html?GetTemperature
could be interpreted as a request to read the temperature from a sensor attached to the board.
The next step was to look at dynamic content. The board is not powerful enough to support conventional technologies such as PHP or ASP. Silverlight offers the ability to move the dynamic content creation away from the web server and onto the client desk top. To demonstrate this, a simple Silverlight application was created to be served by the web server (hence the support for XAP files). The initial version simply said hello to the user.
So far, so good. The web server was serving HTML and Silverlight files to the client.
The next step was to flesh out the Silverlight client to hold sensor data and display this to the user. This part of the application is implemented in MVVM. For this I needed a class to hold a sensor reading and a class (TemperatureReading)to hold a collection of sensor readings (TemperatureViewModel).
public class TemperatureReading
{
///
/// Date and time the reading was recorded.
///
public DateTime When { get; set; }
///
/// Temperature.
///
public double Temperature { get; set; }
///
/// Constructor
///
/// <param name="when" />When was the reding taken
/// <param name="temperature" />Reading taken
public TemperatureReading(DateTime when, double temperature)
{
When = when;
Temperature = temperature;
}
}
public class TemperatureViewModel : INotifyPropertyChanged
{
#region Properties
///
/// Collection of temperature readings.
///
private ObservableCollection _readings;
public ObservableCollection Readings
{
get { return (_readings); }
set
{
_readings = value;
RaisePropertyChanged("Readings", "NumberOfReadings");
}
}
///
/// Number of readings in the collection of temperature readings.
///
public int NumberOfReadings
{
get { return (_readings.Count); }
}
#endregion
#region Constructor(s)
///
/// Default constructor
///
public TemperatureViewModel()
{
Readings = new ObservableCollection();
}
#endregion
#region INotifyPropertyChanged Members
///
/// Event used to notify any subscribers that the data in this class has changed.
///
public event PropertyChangedEventHandler PropertyChanged;
///
/// Let any subscribers know that some data has changed.
///
/// <param name="properties" />Array of name of the properties which have changed.
private void RaisePropertyChanged(params string[] properties)
{
if ((properties != null) && (PropertyChanged != null))
{
foreach (string property in properties)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
#endregion
#region Methods
///
/// Add a new reading to the collection.
///
/// <param name="reading" />Reading to be added.
public void Add(TemperatureReading reading)
{
Readings.Add(reading);
RaisePropertyChanged("Readings", "NumberOfReadings");
}
#endregion
}
Now we have somewhere to store the data we need to display the interface and then add a way of getting the data into the application.
The MainPage.xaml displays the data in a DataGrid and a chart. There is also a button for starting and stopping the collection of data. The DataGrid and the Chart are both bound to an instance of the TemperatureViewModel class.
The data for the class is collected periodically by using a web request from an instance of the WebClient class. This is then parsed and added to the collection of readings and the interface updated automatically through the magic of the RaiseProipertyChanged method of the TemperatureViewModel class.
The source can be found here: SilverlightOnNetduino.zip.
The web server code was modified to provide simulated readings from a temperature sensor. This is simply the current number of milliseconds divided by 100. The data is stored in a DataGrid and a presented to the user:
Adding the Silverlight Toolkit charting control to the application allowed the data to be plotted:
The next step is to tie this up to a real sensor and serve data to the users desktop.
The Firestarter event held at the start of this month saw Microsoft announce the future release of Silverlight 5. A run down of some of the new features can be found here on John Papa’s blog. There is a also a link to the video of Scott Guthrie’s keynote.