Things used in this project

Hardware components:
Pi 3 02
Raspberry Pi 3 Model B
×1
Db410c blue 2a
Qualcomm DragonBoard 410c
×1
Software apps and online services:
10
Microsoft Windows 10 IoT Core
Ide web
Arduino IDE

Code

CONTROLLER.csC#
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Devices.Enumeration;
using Windows.Devices.Gpio;
using Windows.Devices.I2c;
using Windows.Devices.SerialCommunication;
using Windows.Devices.Spi;
using Windows.Networking;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;

namespace IoTController
{
    class CONTROLLER
    {
        private List<I2cDevice> i2cDeviceList;

        public CONTROLLER(string remoteHostname, string localPortName, string remotePortName)
        {
            var now = DateTime.Now;
            Debug.WriteLine(now + " : " + " Controller Unit CONSTRUCTOR");
            i2cDeviceList = new List<I2cDevice>();
            
            RemoteHostname = remoteHostname;
            LocalPortName = localPortName;
            RemotePortName = remotePortName;
            InitGPIOController();
            InitNetworkUPD();
        }

        public string RemoteHostname
        {
            get; set;
        }

        public string LocalPortName
        {
            get; set;
        }

        public string RemotePortName
        {
            get; set;
        }

        private HostName remoteHostname;
        private DatagramSocket socket = new DatagramSocket();
        private DatagramSocket listenerSocket = new DatagramSocket();

        private DataWriter writer;
        private IOutputStream outputStream;

        public async void InitNetworkUPD()
        {
            remoteHostname = new HostName(RemoteHostname);
            listenerSocket.MessageReceived += UDPMessageReceived;
            //listenerSocket.Control.MulticastOnly = true;
            // Start listen operation.

            try
            {
                await listenerSocket.BindServiceNameAsync(LocalPortName); //ServiceName.Text
                //listenerSocket.JoinMulticastGroup(remoteHostname);  //RemoteAddress.Text
            }
            catch (Exception exception)
            {
                listenerSocket.Dispose();
                listenerSocket = null;

                // If this is an unknown status it means that the error is fatal and retry will likely fail.
                if (SocketError.GetStatus(exception.HResult) == SocketErrorStatus.Unknown)
                {
                    throw;
                }

                Debug.WriteLine("Start listening failed with error: " + exception.Message);
            }

            try
            {
                // UPD SENDING SETUP ======================================================
                outputStream = await socket.GetOutputStreamAsync(remoteHostname, RemotePortName);
                // Send out some multicast or broadcast data. Datagrams generated by the IOutputStream will use
                // <source host, source port> information obtained from the parent socket (i.e., 'listenSocket' in
                // this case).
                writer = new DataWriter(outputStream);
            }
            catch (Exception exception)
            {
                Debug.WriteLine("outputStream error: " + exception.Message);
            }
        }

        private void UDPMessageReceived(DatagramSocket socket, DatagramSocketMessageReceivedEventArgs eventArguments)
        {
            try
            {
                // Interpret the incoming datagram's entire contents as a string.
                uint stringLength = eventArguments.GetDataReader().UnconsumedBufferLength;
                string receivedMessage = eventArguments.GetDataReader().ReadString(stringLength);


                Debug.WriteLine(
                    "Received data from remote peer (Remote Address: " +
                    eventArguments.RemoteAddress.CanonicalName +
                    ", Remote Port: " +
                    eventArguments.RemotePort + "): \"" +
                     receivedMessage + "\"");
            }
            catch (Exception exception)
            {
                SocketErrorStatus socketError = SocketError.GetStatus(exception.HResult);

                if (SocketError.GetStatus(exception.HResult) == SocketErrorStatus.Unknown)
                {
                    Debug.WriteLine($"Unknown UDPMessageReceived Error: {exception}");
                }

                Debug.WriteLine("Error happened when receiving a datagram:" + exception.Message);
            }
        }

        public async void Send_UDP(byte[] ReadBuf) //MPUDATA mpudata
        {
            try
            {
                // GetOutputStreamAsync can be called multiple times on a single DatagramSocket instance to obtain
                // IOutputStreams pointing to various different remote endpoints. The remote hostname given to
                // GetOutputStreamAsync can be a unicast, multicast or broadcast address.


                //Array.Copy(ReadBuf, 0, updData, 1, ReadBuf.Length-1);
                writer.WriteBytes(ReadBuf);

                //writer.WriteString(sOut);
                await writer.StoreAsync();
            }
            catch (Exception exception)
            {
                // If this is an unknown status it means that the error is fatal and retry will likely fail.
                if (SocketError.GetStatus(exception.HResult) == SocketErrorStatus.Unknown)
                {
                    Debug.WriteLine($"Unknown Sending UPD Error: {exception}");
                }
            }
        }


        public async Task<I2cDevice> InitI2cCommunication(DEVICE device)
        {
            string aqs = I2cDevice.GetDeviceSelector();                     /* Get a selector string that will return all I2C controllers on the system */
            var dis = await DeviceInformation.FindAllAsync(aqs);            /* Find the I2C bus controller device with our selector string           */

            /* Checking number of I2C ports available
            for (int i=0;i<dis.Count;i++)
            {
                Debug.WriteLine(dis[i].Id.ToString());
            }
            */

            if (dis.Count == 0)
            {
                Debug.WriteLine("No I2C controllers were found on the system");
                return null;
            }

            int I2CPort = (int)device.I2CPort;

            var settings = new I2cConnectionSettings(device.I2C_ADDRESS);
            settings.BusSpeed = I2cBusSpeed.FastMode;
            
            device.I2cCommunication = await I2cDevice.FromIdAsync(dis[I2CPort].Id, settings);    /* Create an I2cDevice with our selected bus controller and I2C settings */

            if (device.I2cCommunication != null)
            {
                i2cDeviceList.Add(device.I2cCommunication); //Debug.WriteLine("i2C List Count: " + i2cDeviceList.Count.ToString());
            }

            else
            {
                Debug.WriteLine($"Slave address {settings.SlaveAddress} on I2C Controller {dis[I2CPort].Id} is currently in use by another application.");
                return null;
            }

            return device.I2cCommunication;
        }

        public async Task<SpiDevice> InitSPICommunication(DEVICE device)
        {
            const string SPI_CONTROLLER_NAME = "SPI0";  /* For DragonBoard, use SPI0                                */
            const Int32 SPI_CHIP_SELECT_LINE = 0;       /* Line 0 maps to physical pin number 12 on the DragonBoard */
            try
            {
                var settings = new SpiConnectionSettings(SPI_CHIP_SELECT_LINE);
                settings.ClockFrequency = 4800000;                              /* 5MHz is the rated speed of the ADXL345 accelerometer                     */
                settings.Mode = SpiMode.Mode3;                                  /* The accelerometer expects an idle-high clock polarity, we use Mode3    
                                                                                 * to set the clock polarity and phase to: CPOL = 1, CPHA = 1         
                                                                                 */

                string aqs = SpiDevice.GetDeviceSelector(SPI_CONTROLLER_NAME);                     /* Get a selector string that will return all SPI controllers on the system */
                var dis = await DeviceInformation.FindAllAsync(aqs);            /* Find the SPI bus controller devices with our selector string             */
                device.SPICommunication = await SpiDevice.FromIdAsync(dis[0].Id, settings);    /* Create an SpiDevice with our bus controller and SPI settings             */
                if (device.SPICommunication == null)
                {
                    Debug.WriteLine($"SPI Controller {dis[0].Id} is currently in use by another application.");
                    return null;
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine("SPI Initialization failed. Exception: " + ex.Message);
                return null;
            }

            return device.SPICommunication;
        }

        public async Task<SerialDevice> InitUARTCommunication(DEVICE device)
        {
            string aqs = SerialDevice.GetDeviceSelector();
            var dis = await DeviceInformation.FindAllAsync(aqs);

            int UARTPort = -1;
            for (int i = 0; i < dis.Count; i++)
            {
                //string stest = dis[i].Id.ToString();
                if (dis[i].Id.ToString().Contains(device.UARTPort))
                {
                    UARTPort = i;
                    break;
                }
            }
            //Debug.WriteLine(dis[UARTPort].Id.ToString());

            if (UARTPort != -1)
            {
                try
                {
                    device.UARTCommunication = await SerialDevice.FromIdAsync(dis[UARTPort].Id);
                    device.UARTCommunication.WriteTimeout = TimeSpan.FromMilliseconds(device.UARTWriteTimeout);
                    device.UARTCommunication.ReadTimeout = TimeSpan.FromMilliseconds(device.UARTReadTimeout);
                    device.UARTCommunication.BaudRate = device.UARTBaudRate;
                    device.UARTCommunication.Parity = SerialParity.None;
                    device.UARTCommunication.StopBits = SerialStopBitCount.One;
                    device.UARTCommunication.DataBits = 8;
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.Message);
                }
            }

            return device.UARTCommunication;
        }

        public GpioController IoController
        {
            get; set;
        }

        public void InitGPIOController()
        {
            IoController = GpioController.GetDefault(); /* Get the default GPIO controller on the system */

            if (IoController == null)
            {
                throw new Exception("GPIO does not exist on the current system.");
            }
        }

        public void InitGPIOInterruptPin(DEVICE device)
        {
            try
            {
                device.IoInterruptPin = IoController.OpenPin(device.IoInterruptPinID);
                //Check if input pull-up resistors are supported
                if (device.IoInterruptPin.IsDriveModeSupported(GpioPinDriveMode.InputPullUp))
                    device.IoInterruptPin.SetDriveMode(GpioPinDriveMode.InputPullUp);
                else
                    device.IoInterruptPin.SetDriveMode(GpioPinDriveMode.Input);

                // Set a debounce timeout to filter out switch bounce noise from a button press
                device.IoInterruptPin.DebounceTimeout = TimeSpan.FromMilliseconds(0);
                //Debug.WriteLine("GPIO pins " + sensor.IoInterruptPinID.ToString() + " initialized correctly.");
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"Fail to Open INTERRUPT Pin: {ex}");
            }            
        }

        public void InitGPIOControlPin(DEVICE device)
        {
            try
            {
                device.IoControlPin = IoController.OpenPin(device.IoControlPinID);
                if (device.IoControlPin == null)
                {
                    return;
                }
                device.IoControlPin.SetDriveMode(GpioPinDriveMode.Output);
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"Fail to Open CONTROL Pin: {ex}");
            }
        }
    }
}
Device.csC#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Devices.Gpio;
using Windows.Devices.I2c;
using Windows.Devices.SerialCommunication;
using Windows.Devices.Spi;
using Windows.Storage.Streams;

namespace IoTController
{
    public enum I2CPortID { I2C0, I2C1 };

    abstract class DEVICE
    {
        public DEVICE()
        {
            this.DeviceName = "Device Name";
            this.DeviceID = 0;
            this.DeviceDescription = " Device Description";
            this.DeviceAvailable = false;
        }

        #region Device Info

        public int DeviceID
        {
            get; set;
        }

        public string DeviceDescription
        {
            get; set;
        }

        public string DeviceName
        {
            get; set;
        }

        public bool DeviceAvailable
        {
            get; set;
        }
        #endregion

        #region SPI-Communication
        public SpiDevice SPICommunication
        {
            get; set;
        }

        public void SPIWriteByte(byte regAddr, byte data)
        {
            byte[] buffer = new byte[2];
            buffer[0] = regAddr;
            buffer[1] = data;
            SPICommunication.Write(buffer);
        }
        #endregion

        #region I2C Communication

        public I2CPortID I2CPort
        {
            get; set;
        }

        public byte I2C_ADDRESS
        {
            get; set;
        }

        public I2cDevice I2cCommunication
        {
            get; set;
        }

        byte[] i2CWriteByte_writeBuffer = new byte[2];
        public void I2CWriteByte(byte regAddr, byte data)
        {
            i2CWriteByte_writeBuffer[0] = regAddr;
            i2CWriteByte_writeBuffer[1] = data;
            I2cCommunication.Write(i2CWriteByte_writeBuffer);
        }

        byte[] i2cReadByte_writeBuffer = new byte[1];
        byte[] i2cReadByte_readBuffer = new byte[1];
        public byte I2CReadByte(byte regAddr)
        {
            i2cReadByte_writeBuffer[0] = regAddr;
            I2cCommunication.WriteRead(i2cReadByte_writeBuffer, i2cReadByte_readBuffer);
            return i2cReadByte_readBuffer[0];
        }

        #endregion

        #region Serial Communication- UART

        public SerialDevice UARTCommunication
        {
            get; set;
        }

        public string UARTPort
        {
            get; set;
        }

        public uint UARTBaudRate
        {
            get; set;
        }

        public int UARTWriteTimeout
        {
            get; set;
        }

        public int UARTReadTimeout
        {
            get; set;
        }

        public DataWriter UARTDataWriteObject
        {
            get; set;
        }
        public DataReader UARTDataReaderObject
        {
            get; set;
        }
        #endregion

        #region GPIO

        public int IoInterruptPinID
        {
            get; set;
        }

        public int IoControlPinID
        {
            get; set;
        }

        public GpioPin IoInterruptPin
        {
            get; set;
        }

        public GpioPin IoControlPin
        {
            get; set;
        }
        #endregion
    }
}
SERVO_CONTROLLER.csC#
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace IoTController
{
    class SERVO_CONTROLLER : DEVICE
    {
        public SERVO_CONTROLLER()
        {
            DeviceName = "Pan & Tilt Controller";
            DeviceID = 456;
            DeviceDescription = "Control Lidar Servos";
            DeviceAvailable = true;
            //UARTPort = "UART1";// UART1 "A700CSCSA"; // \\?\ACPI#QCOM24D4#1#{86e0d1e0-8089-11d0-9ce4-08003e301f73}\UART1 
            // ARDUINO DUE (2) \\?\USB#VID_2341&PID_003D#95333303231351611152#{86e0d1e0-8089-11d0-9ce4-08003e301f73}
            //UARTBaudRate = 115200; // 1 million-bit per second

            UARTReadTimeout = 1000; // ms
            UARTWriteTimeout = 1000; //ms

            //I2C_ADDRESS = 0x08;

            // Create cancellation token object to close I/O operations when closing the device
            //ReadCancellationTokenSource = new CancellationTokenSource();
        }


        /// <summary>
        /// ReadAsync: Task that waits on data and reads asynchronously from the serial device InputStream
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        private Task<UInt32> loadAsyncTask;
        private UInt32 bytesRead;
        public byte ReadAsync(uint ReadBufferLength)
        {
            // Set InputStreamOptions to complete the asynchronous read operation when one or more bytes is available
            //UARTDataReaderObject.InputStreamOptions = InputStreamOptions.ReadAhead; //

            // Create a task object to wait for data on the serialPort.InputStream
            loadAsyncTask = UARTDataReaderObject.LoadAsync(ReadBufferLength).AsTask();

            // Launch the task and wait
            bytesRead = loadAsyncTask.Result;
            if (bytesRead > 0)
            {
                //Debug.WriteLine($"Bytes read = {bytesRead.ToString()}, Data: {UARTDataReaderObject.ReadString(2)}");
                Debug.WriteLine($"Bytes read = {bytesRead.ToString()}, Data: {UARTDataReaderObject.ReadByte()}");
                return 0;//UARTDataReaderObject.ReadByte();
            }
            else
                return 0;
        }

        private Task<UInt32> storeAsyncTask;
        private UInt32 bytesWritten;
        public void ControlServo(byte[] angles)
        {
            try
            {
                if (UARTCommunication != null)
                {
                    byte yawAngle = angles[0];
                    byte pitchAngle = angles[1];
                    byte[] outBuffer = new byte[5];

                    outBuffer[0] = (byte)('R');  //'R' Roll
                    outBuffer[1] = yawAngle;
                    outBuffer[2] = (byte)('P'); ;  // 'P' Pitch
                    outBuffer[3] = pitchAngle;
                    outBuffer[4] = (byte)('\n');  // (ASCII 10, or '\n')
                    UARTDataWriteObject.WriteBytes(outBuffer);

                    // Launch an async task to complete the write operation
                    storeAsyncTask = UARTDataWriteObject.StoreAsync().AsTask();
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }

        }

        byte[] detachServosCommand = new byte[] { (byte)('D'), (byte)('\n') };
        public void DetachServos()
        {
            SendDataServo(detachServosCommand);
            ReadAsync(1);
        }

        byte[] attachServosCommand = new byte[] { (byte)('A'), (byte)('\n') };
        public void AttachServos()
        {
            Debug.WriteLine("AttachServos");
            SendDataServo(attachServosCommand);
            //ReadAsync(1);
        }

        byte[] initializeServosCommand = new byte[] { (byte)('I'), (byte)('\n') };
        public void InitializeServos()
        {
            Debug.WriteLine("InitializeServos");
            SendDataServo(initializeServosCommand);
            ReadAsync(1);
        }

        private void SendDataServo(byte[] data)
        {
            try
            {
                if (UARTCommunication != null)
                {
                    UARTDataWriteObject.WriteBytes(data);

                    // Launch an async task to complete the write operation
                    storeAsyncTask = UARTDataWriteObject.StoreAsync().AsTask();
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
        }

        /// <summary>
        /// CloseDevice:
        /// - Disposes SerialDevice object
        /// - Clears the enumerated device Id list
        /// </summary>
        private void CloseDevice()
        {
            if (UARTCommunication != null)
            {
                UARTCommunication.Dispose();
            }
            UARTCommunication = null;

            Debug.WriteLine("Safely closed Serial Device");

        }

    }
}

Credits

Replications

Did you replicate this project? Share it!

I made one

Love this project? Think it could be improved? Tell us what you think!

Give feedback

Comments

Similar projects you might like

Getting Started with BBC Micro:Bit
Easy
  • 288
  • 8

Full instructions

This tutorial will show you the basics to get started with BBC micro bit.

Windows 10 IoT Core - Reading Heart Rate Pulses
Easy
  • 827
  • 8

Full instructions

In this short blog post, I will show you how to connect a Heart Rate Pulse Sensor to you Raspberry Pi running Windows 10 IoT Core.

A LoRaWAN "The Things Network" Gateway for Windows IoT Core
Easy
  • 2,046
  • 14

Full instructions

Build your own LoRaWAN "The Things Network" packet-forwarding gateway on Windows 10 IoT Core in native .NET code.

Communicating with OBD-2 (On-Board Diagnostics) Systems
Easy
  • 570
  • 6

Protip

Monitoring Vehicle Speed and Engine RPM using ELM327 USB Car Diagnostic Tool and DragonBoard (or Raspberry Pi).

Data visualization in Power BI with BME280 + Raspberry Pi
Easy
  • 689
  • 11

Full instructions

You learn how to visualize real-time sensor data (BME280 + Pi) that your Azure IoT hub receives by Power BI.

Using WiFi Communication (UDP Protocol) - Example 1
Easy
  • 441
  • 5

Protip

Illustrating the use of WiFi communication (UDP protocol) through examples with DragonBoard and Raspberry Pi 3.

Add projectSign up / Login