HomeForaForum_C#d7836eef-6c2c-482f-9453-9b8dc1b2d4dd

C#

administrator ( 11 posts)
1. BLE Serialization
Original post
9/1/2020 12:11:03 PM

Last edited Tuesday, September 1, 2020 1:21 PM

Gravatar

One of the things that needs to be done for BLE is to serialize requests as the Android and or Apple BLE stack cannot handle but one request at a time. I solved this issue with the following class:

    internal class RequestQueue
    {
        #region Fields
        private ConcurrentQueue<IRequest> _requestQueue = new ConcurrentQueue<IRequest>( );
        private ILoggingService _loggingService;
        private readonly Guid _uniqueId;

        #endregion Fields

        #region Public Methods
        public RequestQueue( ILoggingService loggingService, Guid uniqueId )
        {
            _loggingService = loggingService ?? throw new ArgumentNullException( nameof( loggingService ) );
            _uniqueId = uniqueId;
        }

        public void EnqueueRequest( IRequest request )
        {
            if ( request == null )
            {
                throw new ArgumentNullException( nameof( request ) );
            }

            lock ( _requestQueue )  // There ought to be a lockless way of doing this,
            {                       // I'd like to revisit this and see if we can do this sans locks
                _requestQueue.Enqueue( request );

                if ( _requestQueue.Count == 1 )
                {
                    ExecuteRequest( request );
                }
            }

            _loggingService.Info( $"Enqueued {request.Command} ({request.Id})" );

        }

        public void Clear( )
        {
            _requestQueue = new ConcurrentQueue<IRequest>( );
        }
        #endregion Public Methods

        #region Private Methods
        private void ExecuteCharacteristicWriteRequest( CharacteristicWriteRequest characteristicWriteRequest )
        {
            characteristicWriteRequest.Characteristic.CharacteristicWritten += OnCharacteristicWritten;

            Device.BeginInvokeOnMainThread( ( ) =>
            {
                try
                {
                    _loggingService.Info( $"RequestProcessing: Puulse Id {_uniqueId} Executing {characteristicWriteRequest.Command} Id {characteristicWriteRequest.Id}" );
                    characteristicWriteRequest.Characteristic.WriteAsync( characteristicWriteRequest );
                }
                catch ( Exception )
                {
                    _loggingService.Info( $"Device disconnected while writing characteristic" );
                }
            } );

            return;
        }

        private void ExecuteCharacteristicReadRequest( CharacteristicReadRequest characteristicReadRequest )
        {
            characteristicReadRequest.Characteristic.CharacteristicRead += OnCharacteristicRead;

            Device.BeginInvokeOnMainThread( async ( ) =>
            {
                try
                {
                    _loggingService.Info( $"RequestProcessing: Puulse Id {_uniqueId} Executing {characteristicReadRequest.Command} Id {characteristicReadRequest.Id}" );
                    characteristicReadRequest.ValueRead = await characteristicReadRequest.Characteristic.ReadAsync( characteristicReadRequest );
                }
                catch ( Exception )
                {
                    _loggingService.Info( $"Device disconnected while reading characteristic" );
                }
            } );

            return;
        }

        private void ExecuteCharacteristicUpdateRequest( CharacteristicUpdateRequest characteristicUpdateRequest )
        {
            characteristicUpdateRequest.Characteristic.CharacteristicUpdateCompleted += OnCharacteristicUpdateCompleted;

            if ( characteristicUpdateRequest.Enable )
            {
                Device.BeginInvokeOnMainThread( ( ) =>
                {
                    try
                    {
                        _loggingService.Info( $"RequestProcessing: Puulse Id {_uniqueId} Executing {characteristicUpdateRequest.Command} Id {characteristicUpdateRequest.Id}" );
                        characteristicUpdateRequest.Characteristic.StartUpdatesAsync( characteristicUpdateRequest );
                    }
                    catch ( Exception )
                    {
                        _loggingService.Info( $"Device disconnected while starting characteristic updates" );
                    }
                } );
            }
            else
            {
                Device.BeginInvokeOnMainThread( ( ) =>
                {
                    try
                    {
                        _loggingService.Info( $"RequestProcessing: Puulse Id {_uniqueId} Executing {characteristicUpdateRequest.Command} Id {characteristicUpdateRequest.Id}" );
                        characteristicUpdateRequest.Characteristic.StopUpdatesAsync( characteristicUpdateRequest );
                    }
                    catch ( Exception )
                    {
                        _loggingService.Info( $"Device disconnected while stopping characteristic updates" );
                    }
                } );
            }

            return;
        }

        private void ExecuteDescriptorReadRequest( DescriptorReadRequest descriptorReadRequest )
        {
            descriptorReadRequest.Descriptor.DescriptorRead += OnDescriptorRead;

            Device.BeginInvokeOnMainThread( async ( ) =>
            {
                try
                {
                    _loggingService.Info( $"RequestProcessing: Puulse Id {_uniqueId} Executing {descriptorReadRequest.Command} Id {descriptorReadRequest.Id}" );
                    descriptorReadRequest.ValueRead = await descriptorReadRequest.Descriptor.ReadAsync( descriptorReadRequest );
                }
                catch ( Exception )
                {
                    _loggingService.Info( $"Device disconnected while reading descriptor" );
                }
            } );
        }

        private void ExecuteDescriptorWriteRequest( DescriptorWriteRequest descriptorWriteRequest )
        {
            descriptorWriteRequest.Descriptor.DescriptorWritten += OnDescriptorWritten;

            Device.BeginInvokeOnMainThread( ( ) =>
            {
                try
                {
                    _loggingService.Info( $"RequestProcessing: Puulse Id {_uniqueId} Executing {descriptorWriteRequest.Command} Id {descriptorWriteRequest.Id}" );
                    descriptorWriteRequest.Descriptor.WriteAsync( descriptorWriteRequest, null );
                }
                catch
                {
                    _loggingService.Info( $"Device disconnected while writing descriptor" );
                }
            } );
        }

        private void OnCharacteristicUpdateCompleted( object sender, CharacteristicUpdateCompletedEventArgs e )
        {
            e.CharacteristicUpdateRequest.Characteristic.CharacteristicUpdateCompleted -= OnCharacteristicUpdateCompleted;

            _loggingService.Info( $"RequestProcessing: Puulse Id {_uniqueId} Completed {e.CharacteristicUpdateRequest.Command} Id {e.CharacteristicUpdateRequest.Id}" );

            NextRequest( e.CharacteristicUpdateRequest );
        }

        private void OnCharacteristicRead( object sender, CharacteristicReadEventArgs e )
        {
            e.CharacteristicReadRequest.Characteristic.CharacteristicRead -= OnCharacteristicRead;

            _loggingService.Info( $"RequestProcessing: Puulse Id {_uniqueId} Completed {e.CharacteristicReadRequest.Command} Id {e.CharacteristicReadRequest.Id}" );

            NextRequest( e.CharacteristicReadRequest );
        }

        private void OnCharacteristicWritten( object sender, CharacteristicWrittenEventArgs e )
        {
            e.CharacteristicWriteRequest.Characteristic.CharacteristicWritten -= OnCharacteristicWritten;

            NextRequest( e.CharacteristicWriteRequest );
        }

        private void OnDescriptorRead( object sender, DescriptorReadEventArgs e )
        {
            e.DescriptorReadRequest.Descriptor.DescriptorRead -= OnDescriptorRead;

            _loggingService.Info( $"RequestProcessing: Puulse Id {_uniqueId} Completed {e.DescriptorReadRequest.Command} Id {e.DescriptorReadRequest.Id}" );

            NextRequest( e.DescriptorReadRequest );
        }

        private void OnDescriptorWritten( object sender, DescriptorWrittenEventArgs e )
        {
            e.DescriptorWriteRequest.Descriptor.DescriptorWritten -= OnDescriptorWritten;

            _loggingService.Info( $"RequestProcessing: Puulse Id {_uniqueId} Completed {e.DescriptorWriteRequest.Command} Id {e.DescriptorWriteRequest.Id}" );

            if ( e.CharacteristicUpdateRequest != null )
            {
                _loggingService.Info( $"RequestProcessing: Puulse Id {_uniqueId} Completed {e.CharacteristicUpdateRequest.Command} Id {e.CharacteristicUpdateRequest.Id}" );
            }

            NextRequest( e.DescriptorWriteRequest );
        }

        private void NextRequest( IRequest processedRequest )
        {
            IRequest request;

            lock ( _requestQueue )
            {
                _requestQueue.TryDequeue( out request );

                if ( request == null ) // Happens when connecting to a different device while 
                                       // another connect device is in flight
                {
                    return;
                }

                if ( processedRequest.Id != request.Id )
                {
                    //throw new InvalidOperationException( "Id mismatch in the Request Processor" );
                    _loggingService.Info( $"Last id did not match, discarding" );
                }
            }

            _requestQueue.TryPeek( out request );

            ExecuteRequest( request );
        }

        private void ExecuteRequest( IRequest request )
        {
            if ( request != null )
            {
                if ( request.RequestType == RequestType.CharacteristicWrite )
                {
                    CharacteristicWriteRequest characteristicWriteRequest = ( CharacteristicWriteRequest ) request;

                    ExecuteCharacteristicWriteRequest( characteristicWriteRequest );
                    return;
                }

                if ( request.RequestType == RequestType.CharacteristicUpdate )
                {
                    CharacteristicUpdateRequest characteristicUpdateRequest = ( CharacteristicUpdateRequest ) request;

                    ExecuteCharacteristicUpdateRequest( characteristicUpdateRequest );
                    return;
                }

                if ( request.RequestType == RequestType.CharacteristicRead )
                {
                    CharacteristicReadRequest characteristicReadRequest = ( CharacteristicReadRequest ) request;

                    ExecuteCharacteristicReadRequest( characteristicReadRequest );
                    return;
                }

                throw new InvalidOperationException( "" );
            }
        }
        #endregion Private Methods
    }

Replies to this post

0 replies Author Created On Post Number
BLE Serialization administrator 9/1/2020 12:11:03 PM OP
Back to threads