Arduino Forum

Forum 2005-2010 (read only) => Software => Interfacing => Topic started by: vulture on Jan 27, 2010, 08:43 am

Title: Control Arduino with VB.Net/C#
Post by: vulture on Jan 27, 2010, 08:43 am
I am planning to build a simple robot that consists of a (simple) mobile platform, an arduino to control all hardware of that platform and a mini ITX mainboard with windows and .Net to use as 'intelligence'.
I want to use the Arduino (for now) only as a 'bridge' between the Windows environment and the hardware and was looking for ways to connect the Arduino to the .Net framework.
I didn't find really that much 'off the shelf' .Net classes/applications so I decided to create my own.
I never programmed in C before so this is going to be my first try.

What I want to achieve:
A .net Class to be used by my own programs that is capable of writing to the output ports of the Arduino and reading from the input ports.
I also want to 'catch' events when a value of an input pin is changed.
This obviously also needs a sketch on the Arduino to connect to and a kind of 'protocol' to connect this all together.

I'm currently creating and testing the class so the 'protocol' is working as it should.

I would really like to know if someone else is interested in using this class or has a lot of knowledge on the .net part or the C language of the Arduino to give me hints/tips to enhance the code.

I use an Arduino Duemilanove and want to connect the AdaFruit Motorshield and some distance sensors for starters.

If someone is interested I can publish my code so far.
Title: Re: Control Arduino with VB.Net/C#
Post by: erisan500 on Jan 27, 2010, 09:16 am
Hi Vulture,

I'm using VB.net to talk to my arduino and I would like to give your code a look.

Greetings,
EriSan500
Title: Re: Control Arduino with VB.Net/C#
Post by: andrew0 on Jan 27, 2010, 11:41 am
You both might find this page http://www.arduino.cc/playground/Main/InterfacingWithSoftware and in particular this link http://www.acraigie.com/programming/firmatavb/default.html useful.

Andrew
Title: Re: Control Arduino with VB.Net/C#
Post by: vulture on Jan 27, 2010, 01:18 pm
@Andrew. I looked at the links you sugested (of course), but I decided to try and build my own code.
I enjoy doing it (also for educational purposes), so why not.
Another reason I didn't want to use the Firmata solution is that I want to add some functions of my own (like the ones to control the MotorShield) that can be controlled through external .Net code.

I am nearly ready with the initial code so I can test this.
When everything works I will post my code here so the comments can flow in...
(I'm especially interested in de .Net code to do the serial communication because I thing that needs some finetuning...)
Title: Re: Control Arduino with VB.Net/C#
Post by: vulture on Jan 28, 2010, 12:56 pm
OK,
I did some tests today and I think the basics are working.
There is still extra work to do in checking wrong input etc. but that's for later.

Here is the Arduino code:

Code: [Select]


const int dd = 13;                      // highest digital portnumber
const int aa = 5;                       // highest analog portnumber
int D[dd];                              // define digital enables
int R[dd];                              // define digital directions
int T[dd];                              // define digital triggers
int V[dd];                              // define digital values
int A[aa];                              // define analog enables
int S[aa];                              // define analog triggers
int W[aa];                              // define analog values
int cp = 0;                            // char pointer
boolean cfound = false;                    // complete command found
byte stringIn[200];                     // commandbuffer
long previousMillis = 0;                // intervalcheck for watchdog
long interval = 1000;                  // interval between watchdogs
int sa;
byte bt;

void setup() {
 for (int i=0; i <= dd; i++) {
   D[i]=0;                            // enable digital port (default to 0)
   R[i]=0;                            // direction of digital port (0=output, 1=input) (default to 0)
   T[i]=0;                            // enable digital trigger (default to 0)
   V[i]=-1;                            // value of digital port (default to -1 for first trigger)
 }
 for (int i=0; i <= aa; i++) {
   A[i]=0;                            // enable analogl port (default to 0)
   S[i]=0;                            // enable analog trigger (default to 0)
   W[i]=-1;                            // value of analog port (default to -1 for first trigger)
 }

 Serial.begin(9600);
 delay(500);
 Serial.print("(H)");
}

void loop() {
 sa = Serial.available();              // count serial buffer bytes
 if (sa > 0) {                          // if buffer not empty process buffer content
   for (int i=0; i <= sa-1; i++){
     bt = Serial.read();            // read one byte from the serial buffer
     stringIn[cp] = bt;
     cp++;
     if (int(bt) == 41) {            // check for last command char )
       cfound = true;
       break;                             // end for loop
     }
   }
 }

 if (cfound == true) {
   if (int(stringIn[0]) == 40) {      //check if first char of command is (
     exCommand();
   }
   cleanstring();
   cfound = false;
 }

 for (int i=0; i<dd; i++) {           // check all digital ports
   if ((D[i] == 1) && (R[i] == 1)) {  // is port enabled and input?
     int dr = digitalRead(i);
     if (dr != V[i]) {                // value changed?
       V[i] = dr;                     // store value
       if (T[i] == 1) {               // enable trigger?
         Serial.print("(D");
         Serial.print(byte(i));
         Serial.print(byte(V[i]));
         Serial.print(")");
       }
     }
   }
 }
 for (int i=0; i<aa; i++) {            // check analog values
   if (A[i] == 1) {
     int ar = analogRead(i);
     if (ar != W[i]) {                 // value changed?
       if (S[i] > 0) {                 // analog trigger set?
         if (((ar - W[i]) > S[i]) || ((W[i] - ar) > S[i])) {
           Serial.print("(A");
           Serial.print(byte(i));
           Serial.print(highByte(ar));
           Serial.print(lowByte(ar));
           Serial.print(")");
         }
       }
       W[i] = ar;                      // store value
     }
   }
 }

 if (millis() - previousMillis > interval) {
   previousMillis = millis();  
   Serial.print("(H)");                // send watchdog trigger
 }

}

void cleanstring(void) {
 for (int i=0; i<=200; i++) {
   stringIn[i] = 0;                  // null out string
   cp = 0;
 }
}

void exCommand(void) {
 char c = stringIn[1];                // command type
 int n = int(stringIn[2]);            // portnumber
 int v = int(stringIn[3]);            // value
 
 switch (c) {
 case 'D':                        // enable digital pin
   if (v == 1) {
     D[n] = 1;
   }
   else {
     D[n] = 0;
   }
   break;
 case 'A':                        // enable analog pin
   if (v == 1) {
     A[n] = 1;
   }
   else {
     A[n] = 0;
   }
   break;
 case 'R':                        // set direction of digital pin
   switch (v) {
   case 0:                          // input
     R[n] = 0;
     pinMode(n, INPUT);
   case 1:                        // output digital
     R[n] = 1;
     pinMode(n, OUTPUT);
     break;
   case 2:                        // output analog
     R[n] = 2;
     pinMode(n, OUTPUT);
     break;
   }
   break;
 case 'T':                        // set trigger on digital pin
   if (v == 1) {
     T[n] = 1;
   }
   else {
     T[n] = 0;
   }
   break;
 case 'S':                        // set trigger on analog pin
   S[n] = v;
   break;
 case 'V':                        // get value of digital pin
   V[n] = digitalRead(n);
   Serial.print("(D");
   Serial.print(byte(n));
   Serial.print(byte(V[n]));
   Serial.print(")");
   break;
 case 'W':                        // get value of analog pin
   W[n] = analogRead(n);
   Serial.print("(A");
   Serial.print(byte(n));
   Serial.print(highByte(W[n]));
   Serial.print(lowByte(W[n]));
   Serial.print(")");
   break;
 case 'P':                            // write value to digital port
   switch ( R[n]) {
     case 1:                          // digital output
       digitalWrite(n, v);
       break;
     case 2:                          // PWM output
       analogWrite(n, v);
       break;
   }
     break;  
 }

}

Title: Re: Control Arduino with VB.Net/C#
Post by: vulture on Jan 28, 2010, 01:03 pm
I have to post this in two sets...

Code: [Select]

Public Class Arduino_Net
   Private WithEvents serialPort1 As System.IO.Ports.SerialPort
   Private CommandBuffer As String
   Private Receiving As Boolean
   Private BufferPointer As Integer
   Private CBuffer(30) As Byte

   Private _ComPort As String = "COM8"
   Private _BaudRate As Integer = 9600

   'Private WithEvents DataCheckTimer As System.Timers.Timer
   Private WithEvents WatchDogTimer As System.Timers.Timer

   Public Enum DigitalDirection
       Input = 0
       DigitalOutput = 1
       PWMOutput = 2
   End Enum


   Public Event DigitalDataReceived(ByVal DPortNr As Integer, ByVal Value As Integer)

   Public Event AnalogDataReceived(ByVal APortNr As Integer, ByVal Value As Integer)

   Public Event LogMessageReceived(ByVal Message As String, ByVal DebugLevel As Integer)

  Public Event WatchdogReceived()

   Public Event ConnectionLost()

   Public Property ComPort() As String
       Get
           Return _ComPort
       End Get
       Set(ByVal value As String)
           _ComPort = value
       End Set
   End Property

   Public Property BaudRate() As String
       Get
           Return _BaudRate
       End Get
       Set(ByVal value As String)
           _BaudRate = value
       End Set
   End Property

   Public Sub New()
       'DataCheckTimer = New System.Timers.Timer(50)
       'AddHandler DataCheckTimer.Elapsed, AddressOf CheckTimerElapsed
   End Sub

   Public Sub New(ByVal PortName As String)
       Me.ComPort = PortName.Trim
       'DataCheckTimer = New System.Timers.Timer(50)
       'AddHandler DataCheckTimer.Elapsed, AddressOf CheckTimerElapsed
   End Sub

   Public Function StartCommunication() As Boolean
       Dim _ReturnValue As Boolean = False
       Try
           Dim components As System.ComponentModel.IContainer = New System.ComponentModel.Container()
           serialPort1 = New System.IO.Ports.SerialPort(components)
           serialPort1.PortName = _ComPort
           serialPort1.BaudRate = _BaudRate
           serialPort1.ReceivedBytesThreshold = 1

           serialPort1.Open()
           If Not serialPort1.IsOpen Then
               WriteDebug("Unable to open comport...")
               _ReturnValue = False
               Exit Function
           Else
               serialPort1.DtrEnable = True
               WriteDebug("Serial port is open")
               System.Threading.Thread.Sleep(1000)
               Dim Command As Byte() = {40, 0, 0, 0, 41, 0}
               'send some empty commands to clear all buffers on Arduino
               Me.SendCommand(Command)
               Me.SendCommand(Command)
               'DataCheckTimer.Enabled = True
               'DataCheckTimer.Start()
               WatchDogTimer = New System.Timers.Timer(5000)
               WatchDogTimer.Enabled = True
               WatchDogTimer.Start()
               _ReturnValue = True
           End If

           ' callback for text coming back from the arduino
           AddHandler serialPort1.DataReceived, AddressOf OnReceived
       Catch ex As Exception
           WriteDebug("Error opening comport...")
           _ReturnValue = False
       End Try
       Return _ReturnValue
   End Function

   Public Sub SetDigitalDirection(ByVal Port As Integer, ByVal Direction As DigitalDirection)
       'TODO check value and portnumber
       Dim Command1 As Byte() = {40, 82, Port, Direction, 41, 0}
       Me.SendCommand(Command1)
   End Sub

   Public Sub SetDigitalValue(ByVal Port As Integer, ByVal Value As Integer)
       'TODO check value and portnumber
       Dim Command1 As Byte() = {40, 80, Port, Value, 41, 0}
       Me.SendCommand(Command1)
   End Sub

   Public Sub EnableDigitalPort(ByVal Port As Integer, ByVal Enable As Boolean)
       'TODO check value and portnumber
       If Enable Then
           Dim Command1 As Byte() = {40, 68, Port, 1, 41, 0}
           Me.SendCommand(Command1)
       Else
           Dim Command1 As Byte() = {40, 68, Port, 0, 41, 0}
           Me.SendCommand(Command1)
       End If
   End Sub
   Public Sub EnableAnalogPort(ByVal Port As Integer, ByVal Enable As Boolean)
       'TODO check value and portnumber
       If Enable Then
           Dim Command1 As Byte() = {40, 65, Port, 1, 41, 0}
           Me.SendCommand(Command1)
       Else
           Dim Command1 As Byte() = {40, 65, Port, 0, 41, 0}
           Me.SendCommand(Command1)
       End If
   End Sub

   Public Sub EnableDigitalTrigger(ByVal Port As Integer, ByVal Enable As Boolean)
       'TODO check value and portnumber
       If Enable Then
           Dim Command1 As Byte() = {40, 84, Port, 1, 41, 0}
           Me.SendCommand(Command1)
       Else
           Dim Command1 As Byte() = {40, 84, Port, 0, 41, 0}
           Me.SendCommand(Command1)
       End If
   End Sub

   Public Sub EnableAnalogTrigger(ByVal Port As Integer, ByVal Threshold As Integer)
       'TODO check value and portnumber
       Dim Command1 As Byte() = {40, 83, Port, Threshold, 41, 0}
       Me.SendCommand(Command1)
   End Sub

   Public Sub GetDigitalValue(ByVal Port As Integer)
       'TODO check value and portnumber
       Dim Command1 As Byte() = {40, 86, Port, 0, 41, 0}
       Me.SendCommand(Command1)
   End Sub

   Public Sub GetAnalogValue(ByVal Port As Integer)
       'TODO check value and portnumber
       Dim Command1 As Byte() = {40, 87, Port, 0, 41, 0}
       Me.SendCommand(Command1)
   End Sub

   Private Sub SendCommand(ByVal Command As Byte())
       Try
           If Command.Length > 0 Then
               If serialPort1.IsOpen Then
                   serialPort1.Write(Command, 0, Command.Length - 1)
               End If
           End If
       Catch ex As Exception

       End Try
   End Sub

   Private Sub OnReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs)
       If Receiving = False Then
           Receiving = True
           ProcessSerialData()
           Receiving = False
       End If
   End Sub

   Private Sub CheckTimerElapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs)
       If Receiving = False Then
           Receiving = True
           ProcessSerialData()
           Receiving = False
       End If
   End Sub

   Private Sub ProcessSerialData()
       Try
           Dim BytesRead As Integer
           While serialPort1.BytesToRead > 0
               BytesRead = serialPort1.Read(CBuffer, BufferPointer, serialPort1.BytesToRead)
               BufferPointer += BytesRead
               While BufferPointer > 0
                   'search start of new command in buffer
                   Dim CommandStart As Integer = -1
                   For i As Short = 0 To BufferPointer
                       If CBuffer(i) = CByte(40) Then
                           CommandStart = i
                           Exit For
                       End If
                   Next
                   If CommandStart = -1 Then
                       'no begin of command found. this is no valid situation
                       ClearCBuffer()
                   End If
                   If CommandStart > 0 Then
                       'begin of command found somewhere in buffer. dismiss al bytes before startcharacter
                       LeftShiftCBuffer(CommandStart)
                   End If

                   'at this point we should have a clean commandbuffer

                   'search end of command in buffer
                   Dim Commandend As Integer = 0
                   For i As Short = 0 To BufferPointer
                       If CBuffer(i) = CByte(41) Then
                           Commandend = i
                           Exit For
                       End If
                   Next
                   If Commandend > 0 Then
                       'commandend found. there should be a complete command in the buffer
                       Dim CommandBytes(Commandend) As Byte
                       For i As Integer = 0 To Commandend
                           CommandBytes(i) = CBuffer(i)
                       Next
                       'execute command
                       ProcessCommand(CommandBytes)
                       'reset pointer
                       LeftShiftCBuffer(Commandend + 1)
                   Else
                       Exit While
                   End If
               End While
           End While
       Catch ex As Exception
       End Try
   End Sub

   Private Sub ClearCBuffer()
       For i As Integer = 0 To CBuffer.Length - 1
           CBuffer(i) = 0
       Next
       BufferPointer = 0
   End Sub

   Private Sub LeftShiftCBuffer(ByVal NrOfPlaces As Integer)
       For i As Integer = NrOfPlaces To CBuffer.Length - 1
           CBuffer(i - NrOfPlaces) = CBuffer(i)
       Next
       For i As Integer = CBuffer.Length - NrOfPlaces To CBuffer.Length - 1
           CBuffer(i) = 0
       Next
       BufferPointer -= NrOfPlaces
   End Sub
Title: Re: Control Arduino with VB.Net/C#
Post by: vulture on Jan 28, 2010, 01:06 pm
Part 2:

Code: [Select]


   Private Sub ProcessCommand(ByVal CommandBytes As Byte())
       Try
           If ((CommandBytes(0) = CByte(40)) And (CommandBytes(CommandBytes.Length - 1) = CByte(41))) Then
               Dim PType As Char = ChrW(CommandBytes(1))
               Dim PNumber As Integer
               Dim Value As Integer
               Dim CFound As Boolean = False
               Select Case PType
                   Case "D"
                       PNumber = CInt(CommandBytes(2))
                       Value = CInt(CommandBytes(3))
                       RaiseEvent DigitalDataReceived(PNumber, Value)
                   Case "A"
                       PNumber = CInt(CommandBytes(2))
                       Value = (CInt(CommandBytes(3)) * 255) + CInt(CommandBytes(4))
                       RaiseEvent AnalogDataReceived(PNumber, Value)
                   Case "H"
                       PNumber = 0
                       Value = 0
                       RaiseEvent WatchdogReceived()
                       If Not IsNothing(WatchDogTimer) Then
                           WatchDogTimer.Stop()
                           WatchDogTimer.Dispose()
                       End If
                       WatchDogTimer = New System.Timers.Timer(5000)
                       WatchDogTimer.Enabled = True
                       WatchDogTimer.Start()
                   Case "Q"
                       Dim CommandString As String = String.Empty
                       For i As Integer = 0 To CommandBytes.Length - 1
                           CommandString += CommandBytes(i).ToString + " "
                       Next
                       WriteDebug("Arduino Q msg: " + CommandString)
                   Case Else
                       Dim CommandString As String = String.Empty
                       For i As Integer = 0 To CommandBytes.Length - 1
                           CommandString += CommandBytes(i).ToString + " "
                       Next
                       WriteDebug("Arduino msg: " + CommandString)
               End Select
           Else
               Dim CommandString As String = String.Empty
               For i As Integer = 1 To CommandBytes.Length - 1
                   CommandString += CommandBytes(i).ToString
               Next
               WriteDebug("Error:bad commandformat received: " + CommandString)
           End If
       Catch ex As Exception
           WriteDebug("Error:bad commandformat received")
       End Try
   End Sub

   Private Sub WatchdogTimerElaped(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles WatchDogTimer.Elapsed
       RaiseEvent ConnectionLost()
       If Not IsNothing(WatchDogTimer) Then
           WatchDogTimer.Stop()
           WatchDogTimer.Dispose()
       End If
   End Sub

   Private Sub WriteDebug(ByVal Message As String, Optional ByVal Level As Integer = 0)
       RaiseEvent LogMessageReceived(Message, Level)
   End Sub
End Class



I left out most of the comment lines because otherwise it didn't even fit in two posts...

I'm realy interested in the communication part between the Arduino and the .Net Class.
Perhaps there is a more robust way (on the .Net Class side as well as on the Arduino side).
I'm also making a testapplication to demonstrate all the functions of the class and some documentation.

Any comments are welcome.
Title: Re: Control Arduino with VB.Net/C#
Post by: PaulS on Jan 28, 2010, 01:17 pm
You set dd to 13, which results in allocating arrays that can hold 13 values, with indices from 0 to 12. Then, you proceed, in setup, to initialize all 14 values.

You do the same with aa, except that you set it to 5. There are 6 analog ports in each of my Arduinos. Do you have a cheap clone that's missing an analog port?

Code: [Select]
for (int i=0; i <= sa-1; i++)

This would make more sense as:

Code: [Select]
for (int i=0; i < sa; i++)

Why is bt a global variable? sa?

In the block to read the serial data, cp should be initialized before the for loop that populates the stringIn array.

There is no reason to cast the byte bt to an int before comparing it to 41.

What is the significance of 41? Will you remember 6 months from now? Magic numbers, like 41, are to be avoided. Use a #define statement at the top of the program to give a meaningful name to the number, and use that name, instead, throughout the program.

Code: [Select]
#define EOD 41

if(bt == EOD)
{
}


(Change EOD to whatever 41 really means).

Code: [Select]
if (cfound == true)

This is redundant. All you need is:
Code: [Select]
if (cfound)

The expression in the parentheses is evaluated. If the evaluation results in true, the following block is executed. The cfound variable is a boolean, so it, by itself, is either true or false.

Other than these things (some major, some nit-picky), the code looks good. The C# side of things should be interesting, too.
Title: Re: Control Arduino with VB.Net/C#
Post by: erisan500 on Jan 28, 2010, 01:39 pm
Quote
The C# side of things should be interesting, too.


Small correction, Vulture posted VB.Net code.  ;)

Greetings,
EriSan500
Title: Re: Control Arduino with VB.Net/C#
Post by: PaulS on Jan 28, 2010, 03:07 pm
@EriSan500

Those other 2 posts came in while I was hunting and pecking...
Title: Re: Control Arduino with VB.Net/C#
Post by: vulture on Jan 28, 2010, 05:03 pm
@PaulS:

Thanks, that's what I was looking for.
Some solid syntax advice.

As I said, C is new to me, so I'm learning as I go along.
I implemented all of your sugestions (code below) except for one.
You said cp isn't initialized, but it is, namely at the start of the code.
So that should be no problem.

You are right about the arrays.
I'm used to VB.Net and when you define an array there with 14, the array really has 15 values (0-14). But I read the reference information on arrays and you are absolutely right (duh -> GODMember).

And yes, the PC part is in VB.Net and not C#.
I don't think that should be a problem. These classes are completely compatible.

When I have some webspace I will post the complete sketch and .Net project so it's more easy to read/use.
The real VB.Net code has more comment lines, so using this class is realy straight forward.

anyone more comments, on the VB.Net code perhaps?

thanks.
Title: Re: Control Arduino with VB.Net/C#
Post by: vulture on Jan 28, 2010, 05:04 pm
New code with sugested changes:

Code: [Select]


const int dd = 14;                      // number of digital ports
const int aa = 6;                       // number of analog ports
int D[dd];                              // define digital enables
int R[dd];                              // define digital directions
int T[dd];                              // define digital triggers
int V[dd];                              // define digital values
int A[aa];                              // define analog enables
int S[aa];                              // define analog triggers
int W[aa];                              // define analog values
int cp = 0;                            // char pointer
boolean cfound = false;                    // complete command found
byte stringIn[200];                     // commandbuffer
long previousMillis = 0;                // intervalcheck for watchdog
long interval = 1000;                   // interval between watchdogs

#define SOC 40
#define EOC 41

void setup() {
 for (int i=0; i < dd; i++) {
   D[i]=0;                            // enable digital port (default to 0)
   R[i]=0;                            // direction of digital port (0=output, 1=input) (default to 0)
   T[i]=0;                            // enable digital trigger (default to 0)
   V[i]=-1;                            // value of digital port (default to -1 for first trigger)
 }
 for (int i=0; i < aa; i++) {
   A[i]=0;                            // enable analogl port (default to 0)
   S[i]=0;                            // enable analog trigger (default to 0)
   W[i]=-1;                            // value of analog port (default to -1 for first trigger)
 }

 Serial.begin(9600);
 delay(500);
 Serial.print("(H)");
}

void loop() {
 int sa;
 byte bt;
 sa = Serial.available();              // count serial buffer bytes
 if (sa > 0) {                          // if buffer not empty process buffer content
   for (int i=0; i < sa; i++){
     bt = Serial.read();            // read one byte from the serial buffer
     stringIn[cp] = bt;
     cp++;
     if (bt == EOC) {                    // check for last command char )
       cfound = true;
       break;                             // end for loop
     }
   }
 }

 if (cfound) {
   if (int(stringIn[0]) == SOC) {      //check if first char of command is (
     exCommand();
   }
   cleanstring();
   cfound = false;
 }

 for (int i=0; i<dd; i++) {           // check all digital ports
   if ((D[i] == 1) && (R[i] == 1)) {  // is port enabled and input?
     int dr = digitalRead(i);
     if (dr != V[i]) {                // value changed?
       V[i] = dr;                     // store value
       if (T[i] == 1) {               // enable trigger?
         Serial.print("(D");
         Serial.print(byte(i));
         Serial.print(byte(V[i]));
         Serial.print(")");
       }
     }
   }
 }
 for (int i=0; i<aa; i++) {            // check analog values
   if (A[i] == 1) {
     int ar = analogRead(i);
     if (ar != W[i]) {                 // value changed?
       if (S[i] > 0) {                 // analog trigger set?
         if (((ar - W[i]) > S[i]) || ((W[i] - ar) > S[i])) {
           Serial.print("(A");
           Serial.print(byte(i));
           Serial.print(highByte(ar));
           Serial.print(lowByte(ar));
           Serial.print(")");
         }
       }
       W[i] = ar;                      // store value
     }
   }
 }

 if (millis() - previousMillis > interval) {
   previousMillis = millis();  
   Serial.print("(H)");                // send watchdog trigger
 }

}

void cleanstring(void) {
 for (int i=0; i<=200; i++) {
   stringIn[i] = 0;                  // null out string
   cp = 0;
 }
}

void exCommand(void) {
 char c = stringIn[1];                // command type
 int n = int(stringIn[2]);            // portnumber
 int v = int(stringIn[3]);            // value
 
 switch (c) {
 case 'D':                        // enable digital pin
   if (v == 1) {
     D[n] = 1;
   }
   else {
     D[n] = 0;
   }
   break;
 case 'A':                        // enable analog pin
   if (v == 1) {
     A[n] = 1;
   }
   else {
     A[n] = 0;
   }
   break;
 case 'R':                        // set direction of digital pin
   switch (v) {
   case 0:                          // input
     R[n] = 0;
     pinMode(n, INPUT);
   case 1:                        // output digital
     R[n] = 1;
     pinMode(n, OUTPUT);
     break;
   case 2:                        // output analog
     R[n] = 2;
     pinMode(n, OUTPUT);
     break;
   }
   break;
 case 'T':                        // set trigger on digital pin
   if (v == 1) {
     T[n] = 1;
   }
   else {
     T[n] = 0;
   }
   break;
 case 'S':                        // set trigger on analog pin
   S[n] = v;
   break;
 case 'V':                        // get value of digital pin
   V[n] = digitalRead(n);
   Serial.print("(D");
   Serial.print(byte(n));
   Serial.print(byte(V[n]));
   Serial.print(")");
   break;
 case 'W':                        // get value of analog pin
   W[n] = analogRead(n);
   Serial.print("(A");
   Serial.print(byte(n));
   Serial.print(highByte(W[n]));
   Serial.print(lowByte(W[n]));
   Serial.print(")");
   break;
 case 'P':                            // write value to digital port
   switch ( R[n]) {
     case 1:                          // digital output
       digitalWrite(n, v);
       break;
     case 2:                          // PWM output
       analogWrite(n, v);
       break;
   }
     break;  
 }

}

Title: Re: Control Arduino with VB.Net/C#
Post by: PaulS on Jan 28, 2010, 10:17 pm
I was thinking that cp is initialized once, and then incremented in loop. I see that it is reset in clearstring.

The clearstring function isn't really needed. If you changed this:
Code: [Select]
 sa = Serial.available();              // count serial buffer bytes
 if (sa > 0) {                          // if buffer not empty process buffer content
   for (int i=0; i < sa; i++){
     bt = Serial.read();            // read one byte from the serial buffer
     stringIn[cp] = bt;
     cp++;
     if (bt == EOC) {                    // check for last command char )
       cfound = true;
       break;                             // end for loop
     }
   }
 }


to this:
Code: [Select]
 sa = Serial.available();              // count serial buffer bytes
 if (sa > 0) {                          // if buffer not empty process buffer content
   [glow]cp = 0;[/glow]
   for (int i=0; i < sa; i++){
     bt = Serial.read();            // read one byte from the serial buffer
     stringIn[cp] = bt;
     cp++;
       [glow]stringIn[cp] = '\0'; // Add a null at the end[/glow]
     if (bt == EOC) {                    // check for last command char )
       cfound = true;
       break;                             // end for loop
     }
   }
 }


you could get rid of the clearstring function and all calls to it.

I'm not current on VB.net, so I won't comment on that code. That's why I was looking forward to seeing your C# code (after all, that's the topic title). I am conversant with C#.

The thing with god members is something I do not like. The title is conferred on anyone that makes 500 posts - relevant or not, right or not.

I've made some mistakes in some of my posts.
Title: Re: Control Arduino with VB.Net/C#
Post by: vulture on Jan 29, 2010, 07:41 am
@PaulS: the function of the cp variable is to point at the last character in the serial received  buffer.
I'm not realy familiair with it's workings, but in VB.Net the event for receiving serial data is no guarantee that all data is received. So to anticipate on the fact that when serial data is received  there might come more for the same command, I created this 'pointer' to keep track of the last received byte. The clearstring function is called after a complete command is found and not after the serial buffer is read.
I can try your sugestions (everything that can be stripped from this code is in favour of the speed...) and let you know. This will depend on the way VB.Net is sending its serial data.

I'm sorry I let you down with the VB.Net ;-)
The title mentioned 'VB.Net/C#' because these are completely compatible.
I will create a seperate dll from this class and that's useable by VB.Net and C# without changes.
(Perhaps someone is interested in a COM registered dll so it's also compatible with for instance vbscript...)
There are some websites that do VB.Net to C# conversions.
Perhaps you can use them if you want the code in C#.
I started programming in VB.Net some time ago and it's hard to switch to another language after that.
But since the .Net eara VB is a mature language again, so there is really no need for me to switch...
Title: Re: Control Arduino with VB.Net/C#
Post by: PaulS on Jan 29, 2010, 12:55 pm
OK. That makes sense, and is a perfectly reasonable way to do things.

I've got C# code that talks to my Arduino, already, so I wasn't looking for any. But, I was interested in whether you were doing anything different. I'm not really sure it's possible, considering how simple the serial class is in C#.
Title: Re: Control Arduino with VB.Net/C#
Post by: vulture on Jan 29, 2010, 01:37 pm
I didn't use the serial class before in .net.
Usage is easy but it has some 'strange' behaviour that I had to understand.

btw a good resource is this link:
http://blogs.msdn.com/bclteam/archive/2006/10/10/Top-5-SerialPort-Tips-_5b00_Kim-Hamilton_5D00_.aspx

I think a good discussion about the 'efficiency' of code is always desirable, so all input is welcome.

When my webspace is ready I will post a compiled dll to use with some documentation.
Title: Re: Control Arduino with VB.Net/C#
Post by: vulture on Jan 29, 2010, 08:48 pm
OK, I finally got some webspace and copied the compiled dll and arduino sketch.
No further info on the website yet.
I want to add some documentation and perhaps some examples....
(In due time...)

link to the dll:
http://www.gyps.nl/arduino/Arduino_Net.dll

link to the arduino code:
http://www.gyps.nl/arduino/Arduino_net.pde

The rest will follow.
Title: Re: Control Arduino with VB.Net/C#
Post by: erisan500 on Jan 29, 2010, 09:29 pm
Would you also be so kind to put the Visual Studio solution/project there in a zip file?

Greetings,
EriSan500
Title: Re: Control Arduino with VB.Net/C#
Post by: vulture on Jan 30, 2010, 09:11 am
Although it's just work in progress I uploaded the complete VB.Net 2005 project here:

http://www.gyps.nl/arduino/Arduino_Net.zip

This project is not a finished and polished one.
There is one test application in there that I used to test the inputs and outputs. The application works and I included a small text file with the Arduino connections I used.
All the functions in the class are documented, so using the class shouldn't be difficult.

Some explanation here:

To use the digital ports, you have to set the direction of the port (input, output or pwm), enable the port and optionally set a trigger.
When the trigger is set on a digital port, the class fires an event every time the value of that port is changed.
To read a button, attach that button to a digital port, set the direction to input, enable the port and enable the trigger.
When you push the button, an event is fired from the class, saying that the value is changed to 1 and when you release the button, an event is fired saying that the value has changed to 0.
It's also possible to read the current value of a digital port. This function will not give the current value in return, instead it fires the same event as if the trigger was used. This value-read function can be used with or without the use of the trigger.
For an analog port there's only input, so no direction to set here. Just enable the analog port and read the value.
There is also a 'trigger' on the analog port called threshold. This will fire an event when the value of the analog input is changed by more than the set threshold. This will eliminate the slight changes that occur on the analog input.
Reading the value of the analog input works the same as on the digital input. Just use the GetAnalogValue command and wait for the event.

I know it would be more easy if the value reading functions would return a value but this conflict with the working of the Arduino code.
I'm working on that.

Keep in mind that this is no finished product.
There are no real checks on the input values and portnumbers.
These are all to be implemented in the .Net class.

current commands:

StartCommunication() As Boolean
SetDigitalDirection(ByVal Port As Integer, ByVal Direction As DigitalDirection)
SetDigitalValue(ByVal Port As Integer, ByVal Value As Integer)
EnableDigitalPort(ByVal Port As Integer, ByVal Enable As Boolean)
EnableAnalogPort(ByVal Port As Integer, ByVal Enable As Boolean)
EnableDigitalTrigger(ByVal Port As Integer, ByVal Enable As Boolean)
EnableAnalogTrigger(ByVal Port As Integer, ByVal Threshold As Integer)
GetDigitalValue(ByVal Port As Integer)
GetAnalogValue(ByVal Port As Integer)

current events:

DigitalDataReceived(ByVal DPortNr As Integer, ByVal Value As Integer)
AnalogDataReceived(ByVal APortNr As Integer, ByVal Value As Integer)
LogMessageReceived(ByVal Message As String, ByVal DebugLevel As Integer)
WatchdogReceived()
ConnectionLost()


comments are welcome as always.
Title: Re: Control Arduino with VB.Net/C#
Post by: vulture on Feb 01, 2010, 09:46 am
For anyone that's interested, I made a simple page for my code:

http://www.gyps.nl/arduino

In due time I will update this page to something decent, but for now it's just a simple page to keep track of the revisions and changes to the code.
Title: Re: Control Arduino with VB.Net/C#
Post by: vulture on Mar 08, 2010, 02:37 pm
I found out that there was a problem with the links on my website.
I fixed them for the interested people.

I'm also working on a way to add servo support into it.
I am using the Adafruit motorshield, so I'm planning to add all functionality of that to the Arduino_Net project.