Example #1
0
 public void Create_NegativeCapacity_ThrowsArgumentOutOfRangeException()
 {
     AssertExtensions.Throws <ArgumentOutOfRangeException>("capacity", () => WindowsRuntimeBuffer.Create(-1));
     AssertExtensions.Throws <ArgumentOutOfRangeException>("capacity", () => WindowsRuntimeBuffer.Create(new byte[0], 0, 0, -1));
 }
        }  // ReadAsync_MemoryStream

        internal static IAsyncOperationWithProgress <IBuffer, uint> ReadAsync_AbstractStream(Stream stream, IBuffer buffer, uint count,
                                                                                             InputStreamOptions options)
        {
            Debug.Assert(stream != null);
            Debug.Assert(stream.CanRead);
            Debug.Assert(buffer != null);
            Debug.Assert(buffer is IBufferByteAccess);
            Debug.Assert(0 <= count);
            Debug.Assert(count <= int.MaxValue);
            Debug.Assert(count <= buffer.Capacity);
            Debug.Assert(options == InputStreamOptions.None || options == InputStreamOptions.Partial || options == InputStreamOptions.ReadAhead);

            int bytesRequested = (int)count;

            // Check if the buffer is our implementation.
            // IF YES: In that case, we can read directly into its data array.
            // IF NO:  The buffer is of unknown implementation. It's not backed by a managed array, but the wrapped stream can only
            //         read into a managed array. If we used the user-supplied buffer we would need to copy data into it after every read.
            //         The spec allows to return a buffer instance that is not the same as passed by the user. So, we will create an own
            //         buffer instance, read data *directly* into the array backing it and then return it to the user.
            //         Note: the allocation costs we are paying for the new buffer are unavoidable anyway, as we we would need to create
            //         an array to read into either way.

            IBuffer dataBuffer = buffer as WindowsRuntimeBuffer;

            if (dataBuffer == null)
            {
                dataBuffer = WindowsRuntimeBuffer.Create((int)Math.Min((uint)int.MaxValue, buffer.Capacity));
            }

            // This operation delegate will we run inside of the returned IAsyncOperationWithProgress:
            Func <CancellationToken, IProgress <uint>, Task <IBuffer> > readOperation = async(cancelToken, progressListener) =>
            {
                // No bytes read yet:
                dataBuffer.Length = 0;

                // Get the buffer backing array:
                byte[] data;
                int    offset;
                bool   managedBufferAssert = dataBuffer.TryGetUnderlyingData(out data, out offset);
                Debug.Assert(managedBufferAssert);

                // Init tracking values:
                bool done           = cancelToken.IsCancellationRequested;
                int  bytesCompleted = 0;

                // Loop until EOS, cancelled or read enough data according to options:
                while (!done)
                {
                    int bytesRead = 0;

                    try
                    {
                        // Read asynchronously:
                        bytesRead = await stream.ReadAsync(data, offset + bytesCompleted, bytesRequested - bytesCompleted, cancelToken)
                                    .ConfigureAwait(continueOnCapturedContext: false);

                        // We will continue here on a different thread when read async completed:
                        bytesCompleted += bytesRead;
                        // We will handle a cancelation exception and re-throw all others:
                    }
                    catch (OperationCanceledException)
                    {
                        // We assume that cancelToken.IsCancellationRequested is has been set and simply proceed.
                        // (we check cancelToken.IsCancellationRequested later)
                        Debug.Assert(cancelToken.IsCancellationRequested);

                        // This is because if the cancellation came after we read some bytes we want to return the results we got instead
                        // of an empty cancelled task, so if we have not yet read anything at all, then we can throw cancellation:
                        if (bytesCompleted == 0 && bytesRead == 0)
                        {
                            throw;
                        }
                    }

                    // Update target buffer:
                    dataBuffer.Length = (uint)bytesCompleted;

                    Debug.Assert(bytesCompleted <= bytesRequested);

                    // Check if we are done:
                    done = options == InputStreamOptions.Partial || // If no complete read was requested, any amount of data is OK
                           bytesRead == 0 ||                          // this implies EndOfStream
                           bytesCompleted == bytesRequested ||        // read all requested bytes
                           cancelToken.IsCancellationRequested;       // operation was cancelled

                    // Call user Progress handler:
                    if (progressListener != null)
                    {
                        progressListener.Report(dataBuffer.Length);
                    }
                }  // while (!done)

                // If we got here, then no error was detected. Return the results buffer:
                return(dataBuffer);
            };  // readOperation

            return(AsyncInfo.Run <IBuffer, UInt32>(readOperation));
        }  // ReadAsync_AbstractStream
Example #3
0
        private static void DoTestRead(Func <IInputStream> createStreamFunc, InputStreamOptions inputStreamOptions, bool mustInvokeProgressHandler, bool completesSynchronously)
        {
            IInputStream stream = createStreamFunc();
            IBuffer      buffer = WindowsRuntimeBuffer.Create(TestStreamProvider.ModelStreamLength);

            IAsyncOperationWithProgress <IBuffer, uint> readOp = stream.ReadAsync(buffer, (uint)TestStreamProvider.ModelStreamLength, inputStreamOptions);

            if (completesSynchronously)
            {
                // New readOp for a stream where we know that reading is sycnhronous must have Status = Completed
                Assert.Equal(AsyncStatus.Completed, readOp.Status);
            }
            else
            {
                // Note the race. By the tie we get here, the status of the op may be started or already completed.
                AsyncStatus readOpStatus = readOp.Status;
                Assert.True(readOpStatus == AsyncStatus.Completed || readOpStatus == AsyncStatus.Started, "New readOp must have Status = Started or Completed (race)");
            }

            bool progressCallbackInvoked  = false;
            bool completedCallbackInvoked = false;

            uint            readOpId   = readOp.Id;
            EventWaitHandle waitHandle = new ManualResetEvent(false);

            readOp.Progress = (asyncReadOp, bytesCompleted) =>
            {
                progressCallbackInvoked = true;

                // asyncReadOp.Id in a progress callback must match the ID of the asyncReadOp to which the callback was assigned
                Assert.Equal(readOpId, asyncReadOp.Id);

                // asyncReadOp.Status must be 'Started' for an asyncReadOp in progress
                Assert.Equal(AsyncStatus.Started, asyncReadOp.Status);

                // bytesCompleted must be in range [0, maxBytesToRead] asyncReadOp in progress
                Assert.InRange(bytesCompleted, 0u, (uint)TestStreamProvider.ModelStreamLength);
            };

            readOp.Completed = (asyncReadOp, passedStatus) =>
            {
                try
                {
                    completedCallbackInvoked = true;

                    // asyncReadOp.Id in a completion callback must match the ID of the asyncReadOp to which the callback was assigned
                    Assert.Equal(readOpId, asyncReadOp.Id);

                    // asyncReadOp.Status must match passedStatus for a completed asyncReadOp
                    Assert.Equal(passedStatus, asyncReadOp.Status);

                    // asyncReadOp.Status must be 'Completed' for a completed asyncReadOp
                    Assert.Equal(AsyncStatus.Completed, asyncReadOp.Status);

                    IBuffer resultBuffer = asyncReadOp.GetResults();

                    // asyncReadOp.GetResults() must not return null for a completed asyncReadOp
                    Assert.NotNull(resultBuffer);

                    AssertExtensions.GreaterThan(resultBuffer.Capacity, 0u, "resultBuffer.Capacity should be more than zero in completed callback");
                    AssertExtensions.GreaterThan(resultBuffer.Length, 0u, "resultBuffer.Length should be more than zero in completed callback");
                    AssertExtensions.LessThanOrEqualTo(resultBuffer.Length, resultBuffer.Capacity, "resultBuffer.Length should be <= Capacity in completed callback");

                    if (inputStreamOptions == InputStreamOptions.None)
                    {
                        // resultBuffer.Length must be equal to requested number of bytes when an asyncReadOp with
                        // InputStreamOptions.None completes successfully
                        Assert.Equal(resultBuffer.Length, (uint)TestStreamProvider.ModelStreamLength);
                    }

                    if (inputStreamOptions == InputStreamOptions.Partial)
                    {
                        AssertExtensions.LessThanOrEqualTo(resultBuffer.Length, (uint)TestStreamProvider.ModelStreamLength,
                                                           "resultBuffer.Length must be <= requested number of bytes with InputStreamOptions.Partial in completed callback");
                    }
                    buffer = resultBuffer;
                }
                finally
                {
                    waitHandle.Set();
                }
            };

            // Now, let's block until the read op is complete.
            // We speculate that it will complete within 3500 msec, although under high load it may not be.
            // If the test fails we should use a better way to determine if callback is really not invoked, or if it's just too slow.
            waitHandle.WaitOne(500);
            waitHandle.WaitOne(1000);
            waitHandle.WaitOne(2000);

            if (mustInvokeProgressHandler)
            {
                Assert.True(progressCallbackInvoked,
                            "Progress callback specified to ReadAsync callback must be invoked when reading from this kind of stream");
            }

            Assert.True(completedCallbackInvoked,
                        "Completion callback specified to ReadAsync callback must be invoked");

            // readOp.Status must be 'Completed' for a completed async readOp
            Assert.Equal(AsyncStatus.Completed, readOp.Status);

            AssertExtensions.GreaterThan(buffer.Capacity, 0u, "buffer.Capacity should be greater than zero bytes");
            AssertExtensions.GreaterThan(buffer.Length, 0u, "buffer.Length should be greater than zero bytes");
            AssertExtensions.LessThanOrEqualTo(buffer.Length, buffer.Capacity, "buffer.Length <= buffer.Capacity is required for a completed async readOp");

            if (inputStreamOptions == InputStreamOptions.None)
            {
                // buffer.Length must be equal to requested number of bytes when an async readOp with
                //  InputStreamOptions.None completes successfully
                Assert.Equal((uint)TestStreamProvider.ModelStreamLength, buffer.Length);
            }

            if (inputStreamOptions == InputStreamOptions.Partial)
            {
                AssertExtensions.LessThanOrEqualTo(buffer.Length, (uint)TestStreamProvider.ModelStreamLength,
                                                   "resultBuffer.Length must be <= requested number of bytes with InputStreamOptions.Partial");
            }

            byte[] results = new byte[buffer.Length];
            buffer.CopyTo(0, results, 0, (int)buffer.Length);

            Assert.True(TestStreamProvider.CheckContent(results, 0, (int)buffer.Length),
                        "Result data returned from AsyncRead must be the same as expected from the test data source");
        }
        private void SetCommands()
        {
            AddAttachmentCommand = new RelayCommand(async() =>
            {
                var picker = new FileOpenPicker();

                picker.ViewMode = PickerViewMode.List;
                picker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
                picker.FileTypeFilter.Add("*");

                var files = await picker.PickMultipleFilesAsync();
                foreach (var file in files)
                {
                    byte[] bytes = null;
                    using (var stream = await file.OpenReadAsync()) {
                        IBuffer buffer = WindowsRuntimeBuffer.Create((int)stream.Size);
                        await stream.ReadAsync(buffer, (uint)stream.Size, InputStreamOptions.None);
                        bytes = buffer.ToArray();
                    }
                    var attach = new FeedbackAttachment(file.Name, bytes, file.ContentType);
                    this.Attachments.Add(new FeedbackAttachmentVM(attach)
                    {
                        FeedbackMessageVM = this
                    });
                }
            });

            OpenAttachmentCommand = new RelayCommand(async(o) =>
            {
                await((FeedbackAttachmentVM)o).OpenAttachmentAsync();
            });

            SendMessageCommand = new RelayCommand(async(o) =>
            {
                bool success = true;
                if (await ValidateInputAsync())
                {
                    if (NetworkInterface.GetIsNetworkAvailable())
                    {
                        this.IsBusy = true;
                        try
                        {
                            IFeedbackMessage sentMessage = await this.SendFeedbackAsync();
                            this.FeedbackThreadVM.HandleSentMessage(sentMessage);
                        }
                        catch (Exception e)
                        {
                            HockeyClient.Current.AsInternal().HandleInternalUnhandledException(e);
                            success = false;
                        }
                        finally
                        {
                            this.IsBusy = false;
                        }
                        if (!success)
                        {
                            await new MessageDialog(LocalizedStrings.LocalizedResources.FeedbackSendError).ShowAsync();
                            FeedbackFlyoutVM.ShowFlyout();
                        }
                    }
                    else
                    {
                        await new MessageDialog(LocalizedStrings.LocalizedResources.FeedbackNoInternet).ShowAsync();
                        FeedbackFlyoutVM.ShowFlyout();
                    }
                }
                else
                {
                    FeedbackFlyoutVM.ShowFlyout();
                }
            });

            CancelMessageCommand = new RelayCommand((o) => {
                this.Message = null;
                this.Attachments.Clear();
            });

            if (!String.IsNullOrWhiteSpace(this.Email))
            {
                Task t = this.ReLoadGravatar();
            }
            else
            {
                this.Gravatar = GravatarHelper.DefaultGravatar;
            }
        }
        /// <summary>
        /// Asynchronous initialization
        /// </summary>
        /// <returns>Initialization Task</returns>
        public override async Task Init()
        {
            var serviceData = new byte[] {
                0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
                0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
            };

            ServiceData = WindowsRuntimeBuffer.Create(serviceData, 0, serviceData.Length, serviceData.Length);

            await CreateServiceProvider(MSFTServiceUuid);

            GattLocalCharacteristicResult result = null;

            // Prepare the Read Characteristic
            GattLocalCharacteristicParameters readParam = PlainReadParameter;

            readParam.UserDescription = "Microsoft Read characteristic";

            // Add presentation format - 16-bit integer, with exponent 0, the unit is percentage, defined per Bluetooth SIG with Microsoft as descriptor
            readParam.PresentationFormats.Add(
                GattPresentationFormat.FromParts(
                    Convert.ToByte(PresentationFormats.FormatTypes.Signed32BitInteger),
                    PresentationFormats.Exponent,
                    Convert.ToUInt16(PresentationFormats.Units.Unitless),
                    Convert.ToByte(PresentationFormats.NamespaceId.BluetoothSigAssignedNumber),
                    PresentationFormats.Description));

            GattLocalCharacteristic baseReadChar = null;

            result = await ServiceProvider.Service.CreateCharacteristicAsync(MSFTReadChar, readParam);

            GattServicesHelper.GetCharacteristicsFromResult(result, ref baseReadChar);
            if (baseReadChar != null)
            {
                ReadCharacteristic = new Characteristics.MicrosoftReadCharacteristic(baseReadChar, this);
            }

            result = null;

            // Prepare the Write Characteristic
            GattLocalCharacteristicParameters writeParam = PlainWriteOrWriteWithoutRespondsParameter;

            writeParam.UserDescription = "Microsoft Write characteristic";

            // Add presentation format - 16-bit integer, with exponent 0, the unit is percentage, defined per Bluetooth SIG with Microsoft as descriptor
            writeParam.PresentationFormats.Add(
                GattPresentationFormat.FromParts(
                    Convert.ToByte(PresentationFormats.FormatTypes.UTF8String),
                    PresentationFormats.Exponent,
                    Convert.ToUInt16(PresentationFormats.Units.Unitless),
                    Convert.ToByte(PresentationFormats.NamespaceId.BluetoothSigAssignedNumber),
                    PresentationFormats.Description));

            GattLocalCharacteristic baseWriteChar = null;

            result = await ServiceProvider.Service.CreateCharacteristicAsync(MSFTWriteChar, writeParam);

            GattServicesHelper.GetCharacteristicsFromResult(result, ref baseWriteChar);
            if (baseWriteChar != null)
            {
                WriteCharacteristic = new Characteristics.MicrosoftWriteCharacteristic(baseWriteChar, this);
            }

            result = null;

            // Prepare the Notify Characteristic
            GattLocalCharacteristicParameters notifyParam = PlainReadNotifyParameters;

            notifyParam.UserDescription = "Microsoft Notify characteristic";

            // Add presentation format - string, the unit is percentage, defined per Bluetooth SIG with Microsoft as descriptor
            notifyParam.PresentationFormats.Add(
                GattPresentationFormat.FromParts(
                    Convert.ToByte(PresentationFormats.FormatTypes.UTF8String),
                    PresentationFormats.Exponent,
                    Convert.ToUInt16(PresentationFormats.Units.Unitless),
                    Convert.ToByte(PresentationFormats.NamespaceId.BluetoothSigAssignedNumber),
                    PresentationFormats.Description));

            GattLocalCharacteristic baseNotifyChar = null;

            result = await ServiceProvider.Service.CreateCharacteristicAsync(MSFTNotifyChar, notifyParam);

            GattServicesHelper.GetCharacteristicsFromResult(result, ref baseNotifyChar);
            if (baseNotifyChar != null)
            {
                NotifyCharacteristic = new Characteristics.MicrosoftNotifyCharacteristic(baseNotifyChar, this);
            }

            result = null;

            // Prepare the Indicate Characteristic
            GattLocalCharacteristicParameters indicateParam = new GattLocalCharacteristicParameters
            {
                CharacteristicProperties = GattCharacteristicProperties.Read | GattCharacteristicProperties.Indicate,
                WriteProtectionLevel     = GattProtectionLevel.Plain,
                ReadProtectionLevel      = GattProtectionLevel.Plain
            };

            indicateParam.UserDescription = "Microsoft Indicate characteristic";

            // Add presentation format - 16-bit integer, with exponent 0, the unit is percentage, defined per Bluetooth SIG with Microsoft as descriptor
            indicateParam.PresentationFormats.Add(
                GattPresentationFormat.FromParts(
                    Convert.ToByte(PresentationFormats.FormatTypes.UTF8String),
                    PresentationFormats.Exponent,
                    Convert.ToUInt16(PresentationFormats.Units.Unitless),
                    Convert.ToByte(PresentationFormats.NamespaceId.BluetoothSigAssignedNumber),
                    PresentationFormats.Description));

            GattLocalCharacteristic baseIndicateChar = null;

            result = await ServiceProvider.Service.CreateCharacteristicAsync(MSFTIndicateChar, indicateParam);

            GattServicesHelper.GetCharacteristicsFromResult(result, ref baseIndicateChar);
            if (baseIndicateChar != null)
            {
                IndicateCharacteristic = new Characteristics.MicrosoftNotifyCharacteristic(baseIndicateChar, this);
            }

            result = null;

            // Prepare the Read Long Characteristic
            GattLocalCharacteristicParameters longParam = new GattLocalCharacteristicParameters
            {
                CharacteristicProperties = GattCharacteristicProperties.Read,
                WriteProtectionLevel     = GattProtectionLevel.Plain,
                ReadProtectionLevel      = GattProtectionLevel.Plain
            };

            longParam.UserDescription = "Microsoft Read Long characteristic";

            // Add presentation format - 16-bit integer, with exponent 0, the unit is percentage, defined per Bluetooth SIG with Microsoft as descriptor
            longParam.PresentationFormats.Add(
                GattPresentationFormat.FromParts(
                    Convert.ToByte(PresentationFormats.FormatTypes.OpaqueStructure),
                    PresentationFormats.Exponent,
                    Convert.ToUInt16(PresentationFormats.Units.Unitless),
                    Convert.ToByte(PresentationFormats.NamespaceId.BluetoothSigAssignedNumber),
                    PresentationFormats.Description));

            GattLocalCharacteristic baseLongReadChar = null;

            result = await ServiceProvider.Service.CreateCharacteristicAsync(MSFTLongChar, longParam);

            GattServicesHelper.GetCharacteristicsFromResult(result, ref baseLongReadChar);
            if (baseLongReadChar != null)
            {
                ReadLongCharacteristic = new Characteristics.MicrosoftReadLongCharacteristic(baseLongReadChar, this);
            }

            result = null;
        }
Example #6
0
        public async Task ToggleStream(bool start)
        {
            if (start == isStreaming)
            {
                return;
            }
            try
            {
                if (start)
                {
                    if (channels == null)
                    {
                        channels = new List <GattCharacteristic>();
                    }
                    // Get GATT service on start, therefore it will be already available when stopping.
                    deviceService = (await Device.GetGattServicesForUuidAsync(Constants.MUSE_DATA_SERVICE_UUID)).Services.First();
                }
                var characteristics = (await deviceService.GetCharacteristicsAsync()).Characteristics;
                foreach (var c in channelUUIDs)
                {
                    var characteristic = characteristics.SingleOrDefault(x => x.Uuid == c);
                    if (characteristic == null)
                    {
                        Log.Error($"Unexpected null GATT characteristic (UUID={c}) during toggle stream (start={start}).");
                        return;
                    }
                    channels.Add(characteristic);
                }

                GattClientCharacteristicConfigurationDescriptorValue notify;
                byte[] toggleData;

                if (start)
                {
                    notify     = GattClientCharacteristicConfigurationDescriptorValue.Notify;
                    toggleData = Constants.MUSE_TOGGLE_STREAM_START;
                }
                else
                {
                    notify     = GattClientCharacteristicConfigurationDescriptorValue.None;
                    toggleData = Constants.MUSE_TOGGLE_STREAM_STOP;
                }
                var buffer = WindowsRuntimeBuffer.Create(toggleData, 0, toggleData.Length, toggleData.Length);

                for (int i = 0; i < channels.Count; i++)
                {
                    if (start)
                    {
                        channels[i].ValueChanged += Channel_ValueChanged;
                        sampleBuffer              = new Dictionary <ushort, MuseSample>();
                    }
                    else
                    {
                        channels[i].ValueChanged -= Channel_ValueChanged;
                    }
                    await channels[i].WriteClientCharacteristicConfigurationDescriptorAsync(notify);
                }

                // Tell Muse to start or stop notifications.
                await characteristics.Single(x => x.Uuid == Constants.MUSE_TOGGLE_STREAM_UUID).WriteValueWithResultAsync(buffer);
            }
            catch (Exception ex) {
                Log.Error($"Exception during toggle stream (start={start}).", ex);
                if (isStreaming)
                {
                    FinishCloseOffStream();
                }
                return;
            }

            if (start)
            {
                FinishOpenStream();
            }
            else
            {
                FinishCloseOffStream(); // Don't have to keep service reference around anymore. The handlers for the channels will also stop.
            }
        }