/// <summary>
        /// Create a <see cref="DeviceInfoPacket"/> from a <see cref="Device"/>
        /// </summary>
        /// <param name="device"></param>
        /// <returns></returns>
        protected static DeviceInfoPacket EncodeDeviceInfo(Device device)
        {
            DeviceInfoPacket packet = new DeviceInfoPacket();

            unsafe
            {
                SerializeFixedString(device.name, (IntPtr)packet.name.value, DeviceName.Length);
                SerializeFixedString(device.uid, (IntPtr)packet.uid.value, DeviceUID.Length);
                packet.productId = device.productId;
                packet.variantId = device.variantId;
                packet.rssi      = device.rssi;
            }

            return(packet);
        }
        /// <summary>
        /// Decode a device list from a byte stream
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        private static Device[] DecodeDeviceList(byte[] buffer, ref int index)
        {
            DeviceListPacketHeader header = DeserializePacket <DeviceListPacketHeader>(buffer, ref index);

            Device[] devices = new Device[header.deviceCount];
            for (int i = 0; i < header.deviceCount; i++)
            {
                DeviceInfoPacket deviceInfo = DeserializePacket <DeviceInfoPacket>(buffer, ref index);
                Device           device     = DecodeDeviceInfo(deviceInfo, ConnectionState.Disconnected);
                device.isConnected = false;
                devices[i]         = device;
            }

            return(devices);
        }
        /// <summary>
        /// Create a <see cref="DeviceInfoPacket"/> from a <see cref="Device"/>
        /// </summary>
        /// <param name="device"></param>
        /// <returns></returns>
        protected static DeviceInfoPacket SerializeDeviceInfo(Device device)
        {
            DeviceInfoPacket packet = new DeviceInfoPacket();

            unsafe
            {
                SerializeFixedString(device.name, (IntPtr)packet.name.value, DeviceName.Length);
                SerializeFixedString(device.uid, (IntPtr)packet.uid.value, DeviceUID.Length);
                SerializeFixedString(device.firmwareVersion, (IntPtr)packet.firmwareVersion.value, DeviceFirmwareVersion.Length);
                packet.productId         = device.productId;
                packet.variantId         = device.variantId;
                packet.rssi              = device.rssi;
                packet.availableSensors  = device.availableSensors;
                packet.availableGestures = device.availableGestures;
            }

            return(packet);
        }
        /// <summary>
        /// Recreate a <see cref="Device"/> from a <see cref="DeviceInfoPacket"/> and <see cref="ConnectionState"/>
        /// </summary>
        /// <param name="deviceInfoPacket"></param>
        /// <param name="connectionState"></param>
        /// <returns></returns>
        protected static Device DecodeDeviceInfo(DeviceInfoPacket deviceInfoPacket, ConnectionState connectionState)
        {
            Device device;

            unsafe
            {
                device = new Device
                {
                    name        = DeserializeFixedString((IntPtr)deviceInfoPacket.name.value, DeviceName.Length),
                    uid         = DeserializeFixedString((IntPtr)deviceInfoPacket.uid.value, DeviceUID.Length),
                    productId   = deviceInfoPacket.productId,
                    variantId   = deviceInfoPacket.variantId,
                    rssi        = deviceInfoPacket.rssi,
                    isConnected = (connectionState == ConnectionState.Connected)
                };
            }

            return(device);
        }
        /// <summary>
        /// Encode a Device List packet into the buffer
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="index"></param>
        /// <param name="devices"></param>
        public static void EncodeDeviceList(byte[] buffer, ref int index, Device[] devices)
        {
            // Encode header
            PacketHeader header = new PacketHeader(PacketTypeCode.DeviceList);

            SerializePacket(buffer, ref index, header);

            // Encode sub-header
            SerializePacket(buffer, ref index, new DeviceListPacketHeader {
                deviceCount = devices.Length
            });

            // Encode payload
            for (int i = 0; i < devices.Length; i++)
            {
                DeviceInfoPacket packet = EncodeDeviceInfo(devices[i]);
                SerializePacket(buffer, ref index, packet);
            }

            // Encode footer
            SerializePacket(buffer, ref index, _footer);
        }
        /// <summary>
        /// Recreate a <see cref="Device"/> from a <see cref="DeviceInfoPacket"/> and <see cref="ConnectionState"/>
        /// </summary>
        /// <param name="deviceInfoPacket"></param>
        /// <param name="connectionState"></param>
        /// <returns></returns>
        protected static Device DeserializeDeviceInfo(DeviceInfoPacket deviceInfoPacket, ConnectionState connectionState)
        {
            Device device;

            unsafe
            {
                device = new Device
                {
                    name              = DeserializeFixedString((IntPtr)deviceInfoPacket.name.value, DeviceName.Length),
                    uid               = DeserializeFixedString((IntPtr)deviceInfoPacket.uid.value, DeviceUID.Length),
                    firmwareVersion   = DeserializeFixedString((IntPtr)deviceInfoPacket.firmwareVersion.value, DeviceFirmwareVersion.Length),
                    productId         = deviceInfoPacket.productId,
                    variantId         = deviceInfoPacket.variantId,
                    rssi              = deviceInfoPacket.rssi,
                    isConnected       = (connectionState == ConnectionState.Connected),
                    availableSensors  = deviceInfoPacket.availableSensors,
                    availableGestures = deviceInfoPacket.availableGestures
                };
            }

            return(device);
        }