Click here to Skip to main content
15,878,814 members
Articles / Programming Languages / Visual Basic

Sketch framework and Class Library - Part 3

Rate me:
Please Sign up or sign in to vote.
4.29/5 (4 votes)
11 Aug 2016CPOL6 min read 10.1K   109   5   3
Demo Windows Programme for the standard interface for multiple Arduino boards using ArduinoSerialClassLibrary

Introduction

This article discusses the demo programme included with the ArduinoSerialClass library described in Part 2 which itself connects with devices running the a standard Arduino Sketch Framework described in Part 1

Background

The demo programme simply illustrates techniques for using the ArduinoSerialClass Library DLL. This allows an application to connect to a board and automatically discover what values and status information it is returning and what specific commands it will respond to.

If you happen to have a number of boards all doing different things with different sensors and output devices this enables you to have a generic application which will communicate correctly with any of the boards.

For example you many have several different units which are all capable of, amongst other things, reporting the current temperature. Using the standard framework and by making each version report the temperature in the same format you can have an application which will read the temerature from any of the boards.

Using the code

The code bundled with this article is the same as in Part 2. Here we are going to describe how the Demo application uses the ArduinoSerialClassLibrary.

To recap the library has two objects - DetectArduinoClass and ArduinoSerialClass

DetectArduinoClass has a constructor, one public method and one property.

Constructor  New(String) takes an optional String parameter "target" which will be the start of the full name of the port(s) to find. The target defaults to "Arduino".  New() scans the Management Objects looking for serial ports whose name matches the target.

Property PortList is a Dictionary(Of String, String) which will contain a list of all of the ports that match the target name. The short name will be the key (eg COM23) and the full name will be the definition value (eg "Arduino Leonardo (COM23)")

Method  Rescan(String, Boolean) searches the management objects again. The string parameter is again optional as the target name to find, and the boolean parameter if true will clear the existing port list before rescanning.

ArduinoSerialClass is slightly more complex. As well as a constructor New(String) it has two methods GetFullStatus() and DoCmd(String).

Properties Vals, ValDesc, Cmds, Status, StatusDesc, InputPins and OutputPins are all Dictionary(Of String,String). The keys are the identifiers used for particular items and the definitions are the descriptions or, in the case of Vals and Status, the actual values for the particular item. Vals and ValDesc will have the same keys, as will Status and StatusDesc

Turning to the demo program TestApp, it is found as a separate project in the code file consists of a single windows form.

Image 1

On the left is a panel headed "Available Devices". This simply shows the PortList property from a DetectArduinoClass object on form load.

VB.NET
Dim det As New DetectArduinoClass()
'create a DetectArduino object and see what we've found
If det.PortList.Count > 0 Then
    Dim ypos As Integer = 100
    For Each item In det.PortList
       'create label for each one found
        Dim lbl As New Label
        lbl.Name = item.Key
        lbl.Top = ypos
        lbl.AutoSize = True
        lbl.Left = 20
        lbl.Text = item.Key & " = " & item.Value
        grpDevices.Controls.Add(lbl)
        ypos += 20
    Next

In a full application we would probably create a connect button against each item so that we could choose which device to connect to. For now we'll simply connect to the first one found.

VB.NET
Private WithEvents ard As ArduinoSerialClass

'...do the detction stuff as above

    ard = New ArduinoSerialClass(det.PortList.Keys(0))

On the right of the screen we have panels to show the capabilities of the connected board and display its current status values and any dynamic values that are being reported.

When we create the new object ArduinoSerialClass(portname) if the serial port can be opened it immediately requests all the descriptions and status information. This may take a few moments to be updated so we will fire off a timer to give the board time to respond and then interrogate the information returned in the object.

VB.NET
            ard = New ArduinoSerialClass(det.PortList.Keys(0))
            tmrChk.Start()  
'...

    Private Sub tmrChk_Tick(sender As Object, e As EventArgs) Handles tmrChk.Tick
        tmrChk.Stop() 'we only want a one-shot timer
        If ard.PortFound Then
            lblConnected.Text = ard.ComPortName
            lblConnected.BackColor = Color.Green
            grpDeviceInfo.Visible = True
            grpSktechCmds.Visible = True
            grpValues.Visible = True
            ShowStatus()
        Else
            lblConnected.Text = "Not Connected"
            lblConnected.BackColor = Color.Red
            grpDeviceInfo.Visible = False
            grpSktechCmds.Visible = False
            grpValues.Visible = False
        End If
    End Sub

So if the ard object reports that it has connected to the port we can now update the status on the screen

The firmware and hardware info is all in property FStatus

VB.NET
txtStatus.Text = "Unit Name: " & ard.FStatus.UnitID & vbCrLf
txtStatus.Text &= "Firmware: " & ard.FStatus.Sketch & vbCrLf
txtStatus.Text &= "Ver: " & ard.FStatus.Ver & "  "
txtStatus.Text &= "   " & ard.FStatus.CompDate & vbCrLf
txtStatus.Text &= "Author: " & ard.FStatus.Author

The system status which is common to all boards using the framework is in properties SendSerialEnabled and LoopTime.

VB.NET
txtSystemStatus.Text = "Serial values out = " & IIf(ard.SendSerialEnabled,"ON", "OFF") & vbcrlf
If ard.SendSerialEnabled Then
    btnEnableLoop.Text = "Enable Serial Out"
    btnEnableLoop.BackColor = Color.LightPink
Else
    btnEnableLoop.Text = "Disable Serial Out"
    btnEnableLoop.BackColor = Color.LightGreen
End If
txtSystemStatus.Text &= "Arduino Loop Time = " & ard.LoopTime & " ms"
If ard.LoopTime >= numLoop.Minimum Then
    numLoop.Value = ard.LoopTime
Else
    numLoop.Value = numLoop.minimum
End If

We can also have controls to set those properties. In both cases after setting the property we fire off tmrChk again so that it can update any changes once they have been actioned.

VB.NET
Private Sub btnEnableLoop_Click(sender As Object, e As EventArgs) Handles btnEnableLoop.Click
    If ard.PortFound Then
    'simply toggle the property value and wait for a response
        ard.SendSerialEnabled = Not ard.SendSerialEnabled
        tmrChk.Start()
    End If
End Sub

Private Sub btnLoop_Click(sender As Object, e As EventArgs) Handles btnLoop.Click

    If ard.PortFound Then
        ard.LoopTime = numLoop.Value
        'write a silly value into the number control so that we know it gets updated with the status
        numLoop.Value = 999
        tmrChk.Start
    End If
End Sub

For the various descriptors - commands, inputs and outputs, we can just update a text box to list them

VB.NET
txtSketchCmds.Text = ard.Cmds.Count & " Commands reported" & vbcrlf
For Each cmd In ard.Cmds
    txtSketchCmds.Text &= cmd.Key & " " & cmd.Value & vbCrLf
Next

and similarly for the others. To send a command to the unit we have simply provided a textbox to enter the required string and a button to send it. We could dynamically create a separate button and parameter box for each command.

For the unit status and values, we want to read the descriptor from one dictionary (.ValDesc or .StatusDesc) and then the corresponding value from the other dictionary (.Vals or .Status)

VB.NET
txtSketchStatus.Text = ard.StatusDesc.Count & " status report values" & vbCrLf
For Each entry In ard.StatusDesc
    'for each entry in the status description dictionary we will print the description and then use the key to get the relevant value from the status values dictionary
    txtSketchStatus.Text &= entry.Value & " = " & ard.Status(entry.Key) & vbcrlf
Next

'here we iterate through the value descriptions and for each one we create two label controls
'the first holds the description and the second will be updated with the value every time we poll it
Dim ypos As Integer = 55
For Each entry In ard.ValDesc
    Dim lblD As New Label
    lblD.Name = "lblDesc" & entry.Key
    lblD.Top = ypos
    lblD.AutoSize = True
    lblD.Left = 20
    lblD.Text = entry.Value
    grpValues.Controls.Add(lblD)
    Dim lblV As New Label
    lblV.Name = "lbl" & entry.Key
    lblV.Top = ypos + 14
    lblV.AutoSize = True
    lblV.Left = 20
    lblV.Text = "x"
    lblV.Font = New Font(lblV.Font, FontStyle.Bold)
    grpValues.Controls.Add(lblV)
    ypos += 40
Next

For the values we have created Label controls with the name "lbl" & entry.key - for eample lblA

This will enable us to find the appropriate label when we want to update its value when we are polling the board, or in response to an event raised by the ArduinoSerialClass object.

A poll timer, tmrPoll, will be enabled whenever the board is sending serial values. When it fires we will get the values and update them. SInce we may have many values to collect there is a possibility that the _vals structure in the ArduinoSerialClass might get updated whilst we are accessing it which will generate an exception, so we will start by making a local copy of it and working with that.

VB.NET
Dim lbls As Control()
Dim cpy As Dictionary(Of String, String)
Try
    'we are going to make a copy of the values dictionary to work with
    cpy = New Dictionary(Of String, String)(ard.Vals)
    'actually we can still get an exception here if a value is changed whilst the copy is in progress
   ' - you can sort that one out for yourself.
   'It'll probably mean improving ArduinoSerial class with some semaphore
    For Each v In cpy
        'each value will have a label named lblK where K is the key for the value
        lbls = Me.Controls.Find("lbl" & v.Key, True)
        lbls(0).Text = v.Value
    Next
Catch ex As Exception
    ' for now ignore error and don't update any more values
End Try

Note that  lbls() is an array of controls returned by .Find, we are assuming that there is only one control with a matching name and using lbls(0). You can improve this.

And that's really all there is to it. The full code together with the project for the ArduinoSerialClassLib is in the download. You will need Visual Studio to edit this of course.

Assuming you don't want to change anything in the class library you can use the compiled DLL in the bin/release folder. If you are making changes you'll probably be wanting to work with the bin/debug version at first and update the TestApp reference after every compile.

Points of Interest

So we have seen the possible benefits of using a standardised approach to all of our Arduino sktech programmes and having a standard library to access them. Code re-use, more rapid application development focussing on the important stuff at each end - the sensor and device controls in the Arduino sketch and the user interface and data structures at the control PC end.

Of course there is an overhead - you are loading up some of PROGMEM on the Arduino with a lot of string constants that you might not need - you can always trim them down if the real useful code gets too big.

What has been presented here is just one possible way of doing this. You may have your own requirements for a communication - command and response - protocol between the Arduino and the PC. Whatever best suits your particular way of working and applications is the best solution.

This particular format has enabled us to develop a lot of variants on our particular network of things.

I'd be very interested to hear of any suggestions for alternatives and improvements - either as comments on here, or new articles or simply email me.

Stay connected

Roger C-O, August 2016

History

First published 2nd August 2016

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Lead Plymouth University
United Kingdom United Kingdom
Engineering career - originally precision mechanical, then electronic, then computer, then telecommuncations, then marketing, then software and everything else involved in specifying, designing, developing and implementing small systems using hardware, firmware and software.

Expertise in various tools and languages over the years as fashions and requirements shifted. Moved from screwdrivers and soldering irons into 8080 and 6502 machine code and thence to many high level languages.

Currently mostly in a .NET standalone windows and web application environment with SQL server but also using LAMP environment when appropriate.

Retiring soon, but always open for interesting projects that float my old wooden sailing boat.

Comments and Discussions

 
PraiseGreat Pin
George198812-Aug-16 3:35
George198812-Aug-16 3:35 
QuestionYou might want to check the spelling and grammar on this article Pin
marcus obrien8-Aug-16 14:10
marcus obrien8-Aug-16 14:10 
Quite a few spelling mistakes on here.

AnswerRe: You might want to check the spelling and grammar on this article Pin
RogerCreagh11-Aug-16 23:35
RogerCreagh11-Aug-16 23:35 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.