Last edited Tuesday, September 1, 2020 1:21 PM
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
}
0 replies | Author | Created On | Post Number |
---|---|---|---|
BLE Serialization | administrator | 9/1/2020 12:11:03 PM | OP |