Exception thrown when connecting to MetaMotionR device
Hello,
I am currently trying to integrate MetaMotionR device support into our application. I have two MetaMotionR devices. Using the C# tutorials, I managed to connect and retrieve accelerometer data and battery status from them in our application. The problem I have is that sometimes when I try to connect to one of the devices, while connected to the other one, I receive the following exception:
System.Transactions Critical: 0 : <TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Critical"><TraceIdentifier>http://msdn.microsoft.com/TraceCodes/System/ActivityTracing/2004/07/Reliability/Exception/Unhandled</TraceIdentifier><Description>Unhandled exception</Description><AppDomain>Guideline 5.exe</AppDomain><Exception><ExceptionType>System.InvalidOperationException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType><Message>Collection was modified after the enumerator was instantiated.</Message><StackTrace> at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
at System.Collections.Generic.Queue`1.Enumerator.MoveNext()
at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
at MbientLab.MetaWear.Impl.MetaWearBoard.ModuleBoardBridge.&lt;writeValue&gt;d__9.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
at System.Threading.ThreadPoolWorkQueue.Dispatch()</StackTrace><ExceptionString>System.InvalidOperationException: Collection was modified after the enumerator was instantiated.
at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
at System.Collections.Generic.Queue`1.Enumerator.MoveNext()
at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
at MbientLab.MetaWear.Impl.MetaWearBoard.ModuleBoardBridge.&lt;writeValue&gt;d__9.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
at System.Threading.ThreadPoolWorkQueue.Dispatch()</ExceptionString></Exception></TraceRecord>
An unhandled exception of type 'System.InvalidOperationException' occurred in mscorlib.dll Collection was modified after the enumerator was instantiated.
The procedure to close the connection to the previous one and connect to the other one is the following:
Stop the accelerometer of the currently connected sensor using:
public void Stop(IMetaWearBoard device) { if (device == null) { throw new ArgumentNullException("The provided device is null!"); } // Mark the sensor as inactive SensorEnabled = false; var acc = device.GetModule<IAccelerometer>(); // Put accelerometer back into standby mode acc.Stop(); // Stop accelerationi data acc.Acceleration.Stop(); }
Disconnect using:
public async virtual Task Disconnect() { if (_metawearDevice == null) { throw new ArgumentNullException("The MetaWear device instance is null!"); } MBientDeviceConnected = false; _metawearDevice.TearDown(); // Have the board terminate the BLE connection await _metawearDevice.GetModule<IDebug>().DisconnectAsync(); }
Connect to the new device using:
public async virtual Task<IMetaWearBoard> Connect(BluetoothLEDevice device, int retries = 1) { if (device == null) { throw new ArgumentNullException("The provided Bluetooth device is null!"); } _metawearDevice = Application.GetMetaWearBoard(device); // How long the API should wait (in milliseconds) before a required response is received _metawearDevice.TimeForResponse = TimeForResponse; _log.Info($"Connecting to {_metawearDevice.MacAddress}..."); do { try { await _metawearDevice.InitializeAsync(); retries = -1; } catch (Exception e) { _log.Error($"Error connecting to {_metawearDevice.MacAddress}, retrying..."); retries--; } } while (retries > 0); if (retries == 0) { MBientDeviceConnected = false; return null; } else { _log.Info($"Connected to {_metawearDevice.MacAddress}"); MBientDeviceConnected = true; return _metawearDevice; } }
Shortly after the line "_log.Info($"Connected to {_metawearDevice.MacAddress}");" from the "Connect" method (step 3) is executed, the exception mentioned above appears.
My guess is that there are some problems with the connect and disconnect procedure, since sometimes I have to try to connect twice in order to receive accelerometer data, even if the "Connect" method from step 3 returns success every time. The BLE connection interval is set to 7.5ms, the accelerometer's data rate is 100 and the data range is 16.
Can you point me to the direction of the problem? I can give any extra information you need.
Thank you,
Florin
Comments
https://mbientlab.com/community/discussion/3167/how-to-report-an-issue#latest
Hello,
I'm sorry for my negligence.
Board Information:
Hardware revision: 0.4
Firmware revision: 1.4.4
Model number: 5
Host Device Information: Laptop with Windows 10 x64, version 1809.
SDK: I am using Visual Studio 2017, version 15.9.14
Thank you,
Florin
I don't see anything obviously wrong in your code snippets.
The stack trace points to this function but I also don't see how it would be throwing an InvalidOperationException.
Please provide a self contained piece of metawear SDK calls that replicates the issue We should able to copy/paste the code and run it ourselves with minimal effort.
The code to reproduce the problem is the following. What you need is to add objects of type "BluetoothLEDevice" into the list "DeviceList" or to replace the list with a single element. I used the code from the BtleDeviceScanner project from the MetaWear tutorials to create BluetoothLEDevice objects.
What you need to do to recreate the problem is to call the "Connect" method several times consecutively. I found that this exception does not occur in a regular manner.
Thank you,
Florin
Well, there's your problem, you need to wait for async tasks to complete.
Can you please tell me where in the code above do I need to wait for async tasks to complete?
Thank you,
Florin