This project is read-only.
Peripheral profile complete sample (NETMF code targeted to Mountaineer boards, 2 GATT services, 4 GATT characteristics each, read, write and notification samples, use of custom I2C display controller):

using System;
using Microsoft.SPOT;
using TI_BLE_HCI_ClientLib.Controllers;
using Mountaineer.Netmf.Hardware;
using TI_BLE_HCI_ClientLib.DataEntities.Advertising;
using TI_BLE_HCI_ClientLib.HCICommands;
using TI_BLE_HCI_ClientLib.HCIEvents;
using System.Threading;
using Microsoft.SPOT.Hardware;
using Drivers;
using TI_BLE_HCI_ClientLib.Controllers.EnhancedControllers;
using System.Text;
using TI_BLE_HCI_ClientLib.Controllers.GATT_Entities;

namespace TI_BLE_HCI_ClientLib_NETMF.Peripheral.Tester
{
    public class Program
    {
        const string DEVICE_NAME = "NETMF-GATT-Server";
        const byte DISPLAY_I2C_ADDRESS = 0x38;
        static GATTServerController _controller = new GATTServerController(Socket3.SerialPortName, 115200);
        static bool _buttonNotificationEnabled = false;
        static object _buttonNotificationEnabledLocker = new object();
        static byte _valueR;
        static object _valueRLocker = new object();
        static byte _valueG;
        static object _valueGLocker = new object();
        static byte _valueB;
        static object _valueBLocker = new object();
        static PWM _pwmR = new PWM(OnboardIO.PwmRed, 100, 0, false);
        static PWM _pwmG = new PWM(OnboardIO.PwmGreen, 100, 0, false);
        static PWM _pwmB = new PWM(OnboardIO.PwmBlue, 100, 0, false);
        static InterruptPort _btn = new InterruptPort(OnboardIO.Button, true, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeBoth);
        static ByVac_P018_Display _display;
        static string _displayString = string.Empty;
        static object _displayStringLocker = new object();
        static byte _displayR = 10;
        static object _displayRLocker = new object();
        static byte _displayG = 10;
        static object _displayGLocker = new object();
        static byte _displayB = 10;
        static object _displayBLocker = new object();

        public static byte ValueR
        {
            get
            {
                lock (_valueRLocker)
                {
                    return Program._valueR;
                }
            }
            set
            {
                lock (_valueRLocker)
                {
                    Program._valueR = value;
                    _pwmR.DutyCycle = value / 255.0;
                }
            }
        }

        public static byte ValueG
        {
            get
            {
                lock (_valueGLocker)
                {
                    return Program._valueG;
                }
            }
            set
            {
                lock (_valueGLocker)
                {
                    Program._valueG = value;
                    _pwmG.DutyCycle = value / 255.0;
                }
            }
        }

        public static byte ValueB
        {
            get
            {
                lock (_valueBLocker)
                {
                    return Program._valueB;
                }
            }
            set
            {
                lock (_valueBLocker)
                {
                    Program._valueB = value;
                    _pwmB.DutyCycle = value / 255.0;
                }
            }
        }

        public static string DisplayString
        {
            get
            {
                lock (_displayStringLocker)
                {
                    return _displayString;
                }
            }
            set
            {
                lock (_displayStringLocker)
                {
                    _displayString = value;
                    updateDisplayText();
                }
            }
        }

        public static byte DisplayR
        {
            get
            {
                lock (_displayRLocker)
                {
                    return Program._displayR;
                }
            }
            set
            {
                lock (_displayRLocker)
                {
                    Program._displayR = value;
                    updateDisplayRGB();
                }
            }
        }

        public static byte DisplayG
        {
            get
            {
                lock (_displayGLocker)
                {
                    return Program._displayG;
                }
            }
            set
            {
                lock (_displayGLocker)
                {
                    Program._displayG = value;
                    updateDisplayRGB();
                }
            }
        }

        public static byte DisplayB
        {
            get
            {
                lock (_displayBLocker)
                {
                    return Program._displayB;
                }
            }
            set
            {
                lock (_displayBLocker)
                {
                    Program._displayB = value;
                    updateDisplayRGB();
                }
            }
        }

        static bool ButtonNotificationEnabled
        {
            get
            {
                lock (_buttonNotificationEnabledLocker)
                {
                    return Program._buttonNotificationEnabled;
                }
            }
            set
            {
                lock (_buttonNotificationEnabledLocker)
                {
                    Program._buttonNotificationEnabled = value;
                }
            }
        }

        public static void Main()
        {
            Debug.Print("TI_BLE_HCI_ClientLib_NETMF.Peripheral.Tester started.");

            // INIT PERIPHERALS
            initHardware();

            Debug.Print("Starting BLE controller...");

            _controller.Start(DEVICE_NAME);

            Debug.Print("Registering GATT services...");

            // ADD SERVICES
            var service1 = _controller.AddService(0xFFA0);

            service1.AddCharacteristic("LedR",
                GATT_Characteristic.PermissionsEnum.Read | GATT_Characteristic.PermissionsEnum.Write,
                GATT_Characteristic.ValueTypeEnum.UInt8);

            service1.AddCharacteristic("LedG",
                GATT_Characteristic.PermissionsEnum.Read | GATT_Characteristic.PermissionsEnum.Write,
                GATT_Characteristic.ValueTypeEnum.UInt8);

            service1.AddCharacteristic("LedB",
                GATT_Characteristic.PermissionsEnum.Read | GATT_Characteristic.PermissionsEnum.Write,
                GATT_Characteristic.ValueTypeEnum.UInt8);

            service1.AddCharacteristic("ButtonState",
                GATT_Characteristic.PermissionsEnum.Read | GATT_Characteristic.PermissionsEnum.Notify,
                GATT_Characteristic.ValueTypeEnum.Boolean);

            var service2 = _controller.AddService(0xFFB0);

            service2.AddCharacteristic("DisplayText",
                GATT_Characteristic.PermissionsEnum.Read | GATT_Characteristic.PermissionsEnum.Write,
                GATT_Characteristic.ValueTypeEnum.UTF8String);

            service2.AddCharacteristic("DisplayR",
                GATT_Characteristic.PermissionsEnum.Read | GATT_Characteristic.PermissionsEnum.Write,
                GATT_Characteristic.ValueTypeEnum.UInt8);

            service2.AddCharacteristic("DisplayG",
                GATT_Characteristic.PermissionsEnum.Read | GATT_Characteristic.PermissionsEnum.Write,
                GATT_Characteristic.ValueTypeEnum.UInt8);

            service2.AddCharacteristic("DisplayB",
                GATT_Characteristic.PermissionsEnum.Read | GATT_Characteristic.PermissionsEnum.Write,
                GATT_Characteristic.ValueTypeEnum.UInt8);

            if (_controller.RegisterServices())
            {
                Debug.Print("...Succeeded.");
            }
            else
            {
                Debug.Print("...Failed!");
                return;
            }


            // REGISTER TO READ VALUE REQUESTS
            _controller.OnReadCharacteristicValue += _controller_OnReadCharacteristicValue;

            // REGISTER TO WRITE VALUE REQUESTS
            _controller.OnWriteCharacteristicValue += _controller_OnWriteCharacteristicValue;

            // REGISTER TO NOTIFICATION ENABLED CHANGED
            _controller.OnCharacteristicNotificationEnabledChanged += _controller_OnCharacteristicNotificationEnabledChanged;

            // REGISTER TO LINK STATE CHANGES
            _controller.OnLinkStateChanged += _controller_OnLinkStateChanged;

            // MAKE DISCOVERABLE
            Debug.Print("Making Discoverable...");

            if (_controller.MakeDiscoverable())
            {
                Debug.Print("...Succeeded.");
            }
            else
            {
                Debug.Print("...Failed!");
                return;
            }

            // WAITING FOREVER...
            Debug.Print("Waiting for incoming connection...");

            Thread.Sleep(Timeout.Infinite);
        }
        static void updateDisplayText()
        {
            _display.Clear();

            try
            {
                if (_displayString.Length <= 16)
                {
                    _display.Print(0, _displayString);
                }
                else if (_displayString.Length < 32)
                {
                    _display.Print(0, _displayString.Substring(0, 16));
                    _display.Print(1, _displayString.Substring(16));
                }
                else
                {
                    _display.Print(0, "!!!");
                    _display.Print(1, "(" + _displayString.Length.ToString() + ")");
                }
            }
            catch
            {
            }
        }

        static void updateDisplayRGB()
        {
            _display.SetRGBBackground(_displayR, _displayG, _displayB);
        }
        private static void initHardware()
        {
            initDisplay();

            _pwmR.Start();
            _pwmG.Start();
            _pwmB.Start();

            _btn.OnInterrupt += _btn_OnInterrupt;
        }

        private static void uninitHardware()
        {
            _pwmR.DutyCycle = 0;
            _pwmG.DutyCycle = 0;
            _pwmB.DutyCycle = 0;

            _pwmR.Stop();
            _pwmG.Stop();
            _pwmB.Stop();

            _btn.OnInterrupt -= _btn_OnInterrupt;
        }

        static void initDisplay()
        {
            _display = new ByVac_P018_Display(DISPLAY_I2C_ADDRESS);

            _display.Reset();
            Thread.Sleep(500);

            _display.Clear();
            Thread.Sleep(100);

            _display.SetCursorType(0);
            Thread.Sleep(100);

            _display.SetRGBBackground(10, 10, 10);
            Thread.Sleep(100);
        }

        static void _controller_OnLinkStateChanged(object s, GATTServerController.LinkStateEventArgs e)
        {
            if (e.State)
            {
                Debug.Print("Link ESTABLISHED");
            }
            else
            {
                Debug.Print("Link TERMINATED...REBOOTING");

                _controller.Stop();
                uninitHardware();

                PowerState.RebootDevice(false);
            }
        }

        static void _controller_OnReadCharacteristicValue(object s, GATTServerController.CharacteristicValueEventArgs e)
        {
            switch(e.Characteristic.Identifier)
            {
                case "LedR":
                    e.SetValue(ValueR);
                    break;

                case "LedG":
                    e.SetValue(ValueG);
                    break;

                case "LedB":
                    e.SetValue(ValueB);
                    break;

                case "ButtonState":
                    e.SetValue(_btn.Read());
                    break;

                case "DisplayText":
                    e.SetValue(DisplayString);
                    break;

                case "DisplayR":
                    e.SetValue(DisplayR);
                    break;

                case "DisplayG":
                    e.SetValue(DisplayG);
                    break;

                case "DisplayB":
                    e.SetValue(DisplayB);
                    break;
            }
        }

        static void _controller_OnWriteCharacteristicValue(object s, GATTServerController.CharacteristicValueEventArgs e)
        {
            switch (e.Characteristic.Identifier)
            {
                case "LedR":
                    ValueR = e.GetValueAsByte();
                    break;

                case "LedG":
                    ValueG = e.GetValueAsByte();
                    break;

                case "LedB":
                    ValueB = e.GetValueAsByte();
                    break;

               case "DisplayText":
                    DisplayString = e.GetValueAsString();
                    break;

                case "DisplayR":
                    DisplayR = e.GetValueAsByte();
                    break;

                case "DisplayG":
                    DisplayG = e.GetValueAsByte();
                    break;

                case "DisplayB":
                    DisplayB = e.GetValueAsByte();
                    break;
            }
        }

        static void _btn_OnInterrupt(uint data1, uint data2, DateTime time)
        {
            if (!ButtonNotificationEnabled) return;

            try
            {
                if (_controller.RaiseNotification("ButtonState", data2 != 0))
                {
                    Debug.Print("Notification raising Succeeded");
                }
                else
                {
                    Debug.Print("Notification raising Failed");
                }
            }
            catch { }
        }

        static void _controller_OnCharacteristicNotificationEnabledChanged(object s, GATTServerController.CharacteristicNotificationEnabledEventArgs e)
        {
            switch (e.Characteristic.Identifier)
            {
                case "ButtonState":
                    ButtonNotificationEnabled = e.State;
                    break;
            }
        }

    }
}


Central profile sample usage (unit test code, scanning devices):

HCISimpleSerialCentralProfileController controller = new HCISimpleSerialCentralProfileController("COM4", 115200);

controller.Start();

Assert.IsTrue(controller.Reset(HCIController.ResetTypeEnum.HardReset), "Reset() Failed");
Assert.IsTrue(controller.Init(), "Init() Failed");

controller.OnDeviceInformation += ((evt) =>
	{
		Trace.TraceInformation("Device found : {0}", evt.Addr.ToHexString());

		foreach(var ad in evt.AdvertisingAndScanResponseData.AdvertisingDataStructures)
		{
			if(ad is FlagsAdvertisingDataStructure)
			{
				var adFlags=ad as FlagsAdvertisingDataStructure;
				Trace.TraceInformation("\tFlags: {0}", adFlags.ValueBitField.ToString());
				continue;
			}

			if (ad is LocalNameAdvertisingDataStructure)
			{
				var adName = ad as LocalNameAdvertisingDataStructure;
				Trace.TraceInformation("\tLocal Name: {0}", adName.DeviceName);
				continue;
			}

			if (ad is TxPowerLevelAdvertisingDataStructure)
			{
				var adTxPower = ad as TxPowerLevelAdvertisingDataStructure;
				Trace.TraceInformation("\tTx Power Level: {0}", adTxPower.TxPowerLevel);
				continue;
			}

			if (ad is ManufacturerSpecificDataAdvertisingDataStructure)
			{
				var adManufacturerSpecificData = ad as ManufacturerSpecificDataAdvertisingDataStructure;
				Trace.TraceInformation("\tManufacturer Specific Data: {0}", adManufacturerSpecificData.Data.ToHexString());
				continue;
			}

			Trace.TraceWarning("Unknown Advertising Data Structure ! : {0}",ad.Data.ToHexString());
		}
	});

Assert.IsTrue(controller.BeginDeviceDiscovery());

Thread.Sleep(1000);

AutoResetEvent are = new AutoResetEvent(false);

controller.OnDeviceDiscoveryDone += ((evt) =>
	{
		are.Set();
	});

Assert.IsTrue(controller.EndDeviceDiscovery());
Assert.IsTrue(are.WaitOne(1000));

Central profile sample usage (unit test code, connecting to both TI Keyfob and TI SensorTag devices through MAC Address obtained by scanning, as shown in previous code snippet):

HCISimpleSerialCentralProfileController controller = new HCISimpleSerialCentralProfileController("COM4", 115200);

controller.Start();
Assert.IsTrue(controller.Reset(HCIController.ResetTypeEnum.HardReset), "Reset() Failed");
Assert.IsTrue(controller.Init(), "Init() Failed");

ushort connHandleKeyfob;
ushort connHandleSensorTag;

Assert.IsTrue(controller.ConnectTo(TestHelpers.StringWithColonsToByteArrayReversed("90:59:AF:0B:7D:96"), out connHandleKeyfob));
Assert.IsTrue(controller.ConnectTo(TestHelpers.StringWithColonsToByteArrayReversed("90:59:AF:0B:76:29"), out connHandleSensorTag));

Assert.IsTrue(controller.WriteCharacteristic(connHandleSensorTag, 0x006c, (ushort)1));

AutoResetEvent are = new AutoResetEvent(false);

controller.OnNotification += ((notification) =>
{
	if (notification.ConnHandle == connHandleSensorTag)
	{
		switch (notification.ValueAsUInt8)
		{
			case 0x00:
				Assert.IsTrue(controller.WriteCharacteristic(connHandleKeyfob, 0x0028, (byte)0));
				break;

			case 0x01:
				Assert.IsTrue(controller.WriteCharacteristic(connHandleKeyfob, 0x0028, (byte)1));
				break;

			case 0x02:
				Assert.IsTrue(controller.WriteCharacteristic(connHandleKeyfob, 0x0028, (byte)2));
				break;

			case 0x03:
				are.Set();
				break;
		}
	}
});

are.WaitOne();

Assert.IsTrue(controller.WriteCharacteristic(connHandleSensorTag, 0x006c, (ushort)0));

Assert.IsTrue(controller.CloseConnection(connHandleKeyfob));
Assert.IsTrue(controller.CloseConnection(connHandleSensorTag));

Last edited Aug 26, 2014 at 6:20 AM by maiorfi, version 6