Author Topic: Sample Code: C# multithreaded value reader using LibUsbDotNet  (Read 7493 times)

ferzkopp

  • Newbie
  • *
  • Posts: 3
Just wanted to share some code that enables sending analog sensor data from the DigiSpark to a C# program interfaced via LibUsbDotNet (http://sourceforge.net/projects/libusbdotnet/ or http://libusbdotnet.sourceforge.net). The project was to read some analog data into a C# windows program at a relatively low rate (few samples per second is sufficient) in a launch-and-forget fashion.

Here is the DigiSpark code that simply writes some sensor data as a stream of numbers onto the serial port:


#include <DigiUSB.h>

void setup() {
  DigiUSB.begin();
}

int get_sensor() {
  return analogRead(0);
}

void loop() {
  DigiUSB.println(get_sensor(),DEC); 
  DigiUSB.delay(10);
}



Here is the value receiver as a C# class (with associated example). DigiSparkValueReader implements a reader thread which constantly retrieves characters from the interface and parses them into a n integer number. Once the reader was started by a client program, the client can simply access a reader property to retrieve the latest read value.


namespace Examples
{
    using System;
    using System.Text;
    using System.Threading;
    using LibUsbDotNet;
    using LibUsbDotNet.Main;

    /// <summary>
    /// Example program for the DigiSparkValueReader class.
    /// </summary>
    public class DigiSparkValueReaderExample
    {

        /// <summary>
        /// Program's main entry point.
        /// </summary>
        /// <param name="args">Command line arguments</param>
        public static void Main(string[] args)
        {
            DigiSparkValueReader digiSparkReader = new DigiSparkValueReader();           
            while (digiSparkReader.Reading)
            {
                Console.WriteLine("Press enter to retrieve current reader value.");
                Console.ReadKey();
                Console.WriteLine(digiSparkReader.Value);
            }

            digiSparkReader.Dispose();
        }         
    }

    /// <summary>
    /// Reads integers from DigiSpark device.
    /// </summary>
    public class DigiSparkValueReader : IDisposable
    {
        /// <summary>
        /// The DigiSpark USB device.
        /// </summary>
        private UsbDevice usbDevice = null;

        /// <summary>
        /// Standard packet to read data.
        /// </summary>
        private UsbSetupPacket readPacket = new UsbSetupPacket((byte)((0x01 << 5) | 0x80), 0x01, 0, 0, 1);       

        /// <summary>
        /// Flag indicating if resource have been disposed already.
        /// </summary>
        private bool disposed = false;

        /// <summary>
        /// Thread that reads values.
        /// </summary>
        private Thread readerThread = null;

        /// <summary>
        /// Object to synchronize access to value.
        /// </summary>
        private object syncRoot = new object();

        /// <summary>
        /// Value read from DigiSpark
        /// </summary>
        private int value = 0;

        /// <summary>
        /// Creates an instance of the reader and starts the reading thread.
        /// </summary>
        public DigiSparkValueReader()
        {
            UsbDeviceFinder usbFinder = new UsbDeviceFinder(0x16C0, 0x05DF);
            this.usbDevice = UsbDevice.OpenUsbDevice(usbFinder);
            if (this.usbDevice == null)
            {
                throw new ApplicationException("DigiSpark device not found.");
            }

            this.readerThread = new Thread(this.ReadHandler);
            readerThread.Start();
            this.Reading = true;
        }

        /// <summary>
        /// Gets a flag indicating wether the reader is still reading.
        /// </summary>
        public bool Reading
        {
            get;
            private set;
        }

        /// <summary>
        /// Get a flag with the most recent value read.
        /// </summary>
        public int Value
        {
            get
            {
                lock (syncRoot)
                {
                    return this.value;
                }
            }
        }

        /// <summary>
        /// Thread performing the read and value conversion operation.
        /// </summary>
        private void ReadHandler()
        {
            // String accumulator to hold largest integer string "-2147483648" (11 bytes)
            StringBuilder currentLine = new StringBuilder(11);
            byte[] ctrlData = new byte[1];

            // Reading loop
            while(this.Reading)
            {
                ctrlData[0] = 0;
                while (ctrlData[0] != 4)
                {
                    // Attempt to read one byte from device
                    ctrlData[0] = 4;
                    int transferred;
                    bool result = this.usbDevice.ControlTransfer(ref this.readPacket, ctrlData, 1, out transferred);
                    if (!result)
                    {
                        // Read error
                        this.Reading = false;
                        break;
                    }

                    // No data read
                    if (ctrlData[0] == 4)
                    {
                        break;
                    }

                    // Process read ASCII character
                    char currentCharacter = Convert.ToChar(ctrlData[0]);
                    if (((currentCharacter.Equals('\r') || currentCharacter.Equals('\n')) && currentLine.Length > 0) ||
                         (currentLine.Length == currentLine.Capacity))
                    {
                        // Line terminated or buffer full, parse line into number and reset line
                        int currentValue;
                        if (int.TryParse(currentLine.ToString(), out currentValue))
                        {
                            lock (this.syncRoot)
                            {
                                this.value = currentValue;
                            }
                        }

                        currentLine.Length = 0;
                    }
                    else if (char.IsDigit(currentCharacter) || currentCharacter.Equals('-'))
                    {
                        // Accumulate number in a buffer
                        currentLine.Append(currentCharacter);
                    }
                }

                // Pause reading thread
                System.Threading.Thread.Sleep(10);
            }
        }

        /// <summary>
        /// Dispose resources
        /// </summary>
        /// <param name="disposing">Flag indicating if we are disposing</param>
        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    // Stop thread
                    if (this.readerThread != null)
                    {
                        this.readerThread.Abort();
                    }

                    // Close device
                    if (this.usbDevice != null)
                    {
                        if (this.usbDevice.IsOpen)
                        {
                            IUsbDevice wholeUsbDevice = usbDevice as IUsbDevice;
                            this.usbDevice.Close();
                        }
                    }

                    this.usbDevice = null;
                    UsbDevice.Exit();
                }

                this.disposed = true;
            }
        }

        /// <summary>
        /// Dispose resources
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    }
}


gogol

  • Sr. Member
  • ****
  • Posts: 398
Re: Sample Code: C# multithreaded value reader using LibUsbDotNet
« Reply #1 on: June 23, 2014, 03:51:28 am »
can you please modify your post and use the CODE-Tag for your source code?
That makes code better readable, avoids line-breaks and other formatting quirks