How to create a watcherprocess to detect a removeable USB Device? - c#

I build a little script that checks if a USB Stick with a given Name ist plugged into the Computer, but now I want to build a service around this Script to watch if the Stick plugged in or not. At first I try to do this with the filewatcher and create a file on the Stick but if remove the stick from the pc and replugged the filewatcher dosent realize it. The following script check one time if the Stick is plugged in or not, but I need a script to loop this DriveInfo.GetDrive function. I dont know if the best way is to buil a 10 second timer loop around this function or if there is any watcher class for removeable devices in the .NET Framework. Here comes the Script:
public static void Main()
{
Run();
}
public static void Run()
{
var drives = DriveInfo.GetDrives()
.Where(drive => drive.IsReady && drive.DriveType == DriveType.Removable);
if (drives.Count() > 0)
{
foreach (var drive in drives)
{
if (drive.VolumeLabel == "TESTLABEL") Console.WriteLine("USB Stick is plugged in");
}
}
}

You can hook to (USB) Events using the ManagementEventWatcher.
Working example for LinqPad paraphrasing this neat answer which uses the Win32_DeviceChangeEvent:
// using System.Management;
// reference System.Management.dll
void Main()
{
using(var control = new USBControl()){
Console.ReadLine();//block - depends on usage in a Windows (NT) Service, WinForms/Console/Xaml-App, library
}
}
class USBControl : IDisposable
{
// used for monitoring plugging and unplugging of USB devices.
private ManagementEventWatcher watcherAttach;
private ManagementEventWatcher watcherDetach;
public USBControl()
{
// Add USB plugged event watching
watcherAttach = new ManagementEventWatcher();
watcherAttach.EventArrived += Attaching;
watcherAttach.Query = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2");
watcherAttach.Start();
// Add USB unplugged event watching
watcherDetach = new ManagementEventWatcher();
watcherDetach.EventArrived += Detaching;
watcherDetach.Query = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 3");
watcherDetach.Start();
}
public void Dispose()
{
watcherAttach.Stop();
watcherDetach.Stop();
//you may want to yield or Thread.Sleep
watcherAttach.Dispose();
watcherDetach.Dispose();
//you may want to yield or Thread.Sleep
}
void Attaching(object sender, EventArrivedEventArgs e)
{
if(sender!=watcherAttach)return;
e.Dump("Attaching");
}
void Detaching(object sender, EventArrivedEventArgs e)
{
if(sender!=watcherDetach)return;
e.Dump("Detaching");
}
~USBControl()
{
this.Dispose();// for ease of readability I left out the complete Dispose pattern
}
}
When attaching a USB-Stick I'll receive 7 attach (resp. detach) Events. Customize the Attaching/Detaching methods as you like. The blocking part is left to the reader, depending on his needs, with a Windows Service you wouldn't need to block at all.

Related

DeviceWatcher Updated and Removed events never fire

I am trying to use a DeviceWatcher to listen for a usb device. If the device is plugged in when my app starts, the Added event fires just fine and I can connect. But if I plug the device in after my app starts, or if I unplug the device, no other events fire. I have added callbacks to Added, Removed, and Updated, which is what the documentation said needed to have callbacks for the thing to work. What am I missing?
private void Watcher_DeviceAdded(DeviceWatcher sender, DeviceInformation deviceInfo) {
// Watcher may have stopped while we were waiting for our chance to run.
if (IsWatcherStarted(sender)) {
_resultCollection.Add(deviceInfo);
RaiseDeviceChanged(sender, deviceInfo.Id);
}
}
private void Watcher_DeviceUpdated(DeviceWatcher sender, DeviceInformationUpdate deviceInfoUpdate) {
// Watcher may have stopped while we were waiting for our chance to run.
if (IsWatcherStarted(sender)) {
// Find the corresponding updated DeviceInformation in the collection and pass the update object
// to the Update method of the existing DeviceInformation. This automatically updates the object
// for us.
foreach (var deviceInfoDisp in _resultCollection) {
if (deviceInfoDisp.Id == deviceInfoUpdate.Id) {
deviceInfoDisp.Update(deviceInfoUpdate);
RaiseDeviceChanged(sender, deviceInfoUpdate.Id);
break;
}
}
}
}
private void Watcher_DeviceRemoved(DeviceWatcher sender, DeviceInformationUpdate deviceInfoUpdate) {
// Watcher may have stopped while we were waiting for our chance to run.
if (IsWatcherStarted(sender)) {
// Find the corresponding DeviceInformation in the collection and remove it
foreach (var deviceInfoDisp in _resultCollection) {
if (deviceInfoDisp.Id == deviceInfoUpdate.Id) {
_resultCollection.Remove(deviceInfoDisp);
break;
}
}
RaiseDeviceChanged(sender, deviceInfoUpdate.Id);
}
}
I realized I had passed the wrong VID and PID to the watcher. I am using the Windows.Devices.SerialCommunication.SerialDevice class to get the device selector, and I passed the wrong IDs to the static method.

BLE advertisement UWP application

Im trying to make a program that can scan for BLE advertisements. I have been looking at the Windows-universal-samples, more precisely the sample called BluetoothAdvertisement. I want to make a simple UWP application that can scan for BLE advertisements and show them in a listbox. But my application can't find anything at all and I'm totally lost.
namespace BleDiscAdv2
{
public sealed partial class MainPage : Page
{
// The Bluetooth LE advertisement watcher class is used to control and customize Bluetooth LE scanning.
private BluetoothLEAdvertisementWatcher watcher;
public MainPage()
{
this.InitializeComponent();
// Create and initialize a new watcher instance.
watcher = new BluetoothLEAdvertisementWatcher();
//Set the in-range threshold to -70dBm. This means advertisements with RSSI >= -70dBm
//will start to be considered "in-range"
watcher.SignalStrengthFilter.InRangeThresholdInDBm = -70;
// Set the out-of-range threshold to -75dBm (give some buffer). Used in conjunction with OutOfRangeTimeout
// to determine when an advertisement is no longer considered "in-range"
watcher.SignalStrengthFilter.OutOfRangeThresholdInDBm = -75;
// Set the out-of-range timeout to be 2 seconds. Used in conjunction with OutOfRangeThresholdInDBm
// to determine when an advertisement is no longer considered "in-range"
watcher.SignalStrengthFilter.OutOfRangeTimeout = TimeSpan.FromMilliseconds(2000);
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
// Attach a handler to process the received advertisement.
// The watcher cannot be started without a Received handler attached
watcher.Received += OnAdvertisementReceived;
}
private void btStart_Click(object sender, RoutedEventArgs e)
{
watcher.Start();
}
private async void OnAdvertisementReceived(BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementReceivedEventArgs eventArgs)
{
DateTimeOffset timestamp = eventArgs.Timestamp;
string localName = eventArgs.Advertisement.LocalName;
await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
lbModtaget.Items.Add("Name of device: " + localName + "\t" + "Time for advertisement: " + timestamp.ToString("hh\\:mm\\:ss\\.fff"));
});
}
}
}
Can someone tell me what is wrong?
I'm new to BLE and I haven't been coding for a while.
Best regards
Christian
But my application can't find anything at all and I'm totally lost.
Please ensure that your app has enable Bluetooth capability in the Package.appxmanifest. See Basic Setup for details.
Please ensure the Bluetooth radio of running device was turn on and available.
There're devices are advertising and meet the filter. You can run the Scenario 2 of the Bluetooth advertisement official sample on another device to ensure that.
By testing on my side, your code snippet can scan the BLE advertisements well. In your code snippet, you didn't listen to the Stopped event handle of the watcher which is for notification to the app that the Bluetooth LE scanning for advertisements has been cancelled or aborted either by the app or due to an error. If the watcher is force stopped it will not get any advertisements.
You can add the Stopped event handle to check if there is a BluetoothError.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
// Attach a handler to process the received advertisement.
// The watcher cannot be started without a Received handler attached
watcher.Received += OnAdvertisementReceived;
watcher.Stopped += OnAdvertisementWatcherStopped;
}
private async void OnAdvertisementWatcherStopped(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementWatcherStoppedEventArgs args)
{
await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
txtresult.Text = string.Format("Watcher stopped or aborted: {0}", args.Error.ToString());
});
}
For example, RadioNotAvailable may be caused by the running device is not enable the Bluetooth, OtherError may be caused by Bluetooth capability doesn't enabled. If the watcher is not stopped and there're advertisements, your app should work.

Windows 10 Bluetooth Low Energy Connection c#

For a project I need to get some data from a Bluetooth device on windows 10 using C#. I'm not too familiar with the Bluetooth API and can't figure out why the following is not working:
Using the BluetoothLEAdvertisementWatcher I search for advertisements, which works fine. I do receive the advertisement from the device (local name fits) as well as it's ServiceUuids. Next I try to connect to the device using the BluetoothAddress received together with the advertisement:
private async void OnAdvertisementReceived(BluetoothLEAdvertisementWatcher watcher,
BluetoothLEAdvertisementReceivedEventArgs eventArgs)
{
ulong blAdress = eventArgs.BluetoothAddress;
BluetoothLEDevice blDevice = await
Windows.Devices.Bluetooth.BluetoothLEDevice.FromBluetoothAddressAsync(blAdress);
}
However, doing so results in an exception:
Element not found. (Exception from HRESULT: 0x80070490).
Is this the correct way to read data from the device? Are other options available to read the data from the services? Manually pairing the device in windows is not really an option and also seems to fail.
/Edit 1: I check for the local name of the device to make sure I only try to connect to the right one. So I guess there is a problem with connecting to this specific device, still I have no idea how to work around that. The service data was succesfully read on iOS, so it should be possible.
Until MS fixes this problem the only reliable solution to this I have found to connect to a BLE device is to ask the registry for a list of paired BLE devices and compare the bluetooth address in the advert with with registry list of paired able devices. My experience is that when FromBluetoothAddressAsync is called on an unpaired device Windows throws an exception and kills the watcher thread. I have some C++ code that I am happy to share that reads the registry and creates a list of paired BLE devices.
Hopefully MS will take the time to fully support BLE in the same manner Apple does.
Here is a reference from MS (https://social.msdn.microsoft.com/Forums/vstudio/en-US/e321cb3c-462a-4b16-b7e4-febdb3d0c7d6/windows-10-pairing-a-ble-device-from-code?forum=wdk). It seems that to use this BluetoothLEDevice.FromBluetoothAddressAsync we have to handle the exception when the device is advertising and not yet paired.
I got the same issue when I using the BluetoothLEAdvertisementWatcher directly.
Then I tested the different addresses listed by the watcher. I found it is related to the Bluetooth devices.
After adding the filter as following, I can connect to GATT device (TI Sensor Tag) successfully.
public sealed partial class MainPage : Page
{
private BluetoothLEAdvertisementWatcher watcher;
public MainPage()
{
this.InitializeComponent();
// Create and initialize a new watcher instance.
watcher = new BluetoothLEAdvertisementWatcher();
// Part 1B: Configuring the signal strength filter for proximity scenarios
// Configure the signal strength filter to only propagate events when in-range
// Please adjust these values if you cannot receive any advertisement
// Set the in-range threshold to -70dBm. This means advertisements with RSSI >= -70dBm
// will start to be considered "in-range".
watcher.SignalStrengthFilter.InRangeThresholdInDBm = -70;
// Set the out-of-range threshold to -75dBm (give some buffer). Used in conjunction with OutOfRangeTimeout
// to determine when an advertisement is no longer considered "in-range"
watcher.SignalStrengthFilter.OutOfRangeThresholdInDBm = -75;
// Set the out-of-range timeout to be 2 seconds. Used in conjunction with OutOfRangeThresholdInDBm
// to determine when an advertisement is no longer considered "in-range"
watcher.SignalStrengthFilter.OutOfRangeTimeout = TimeSpan.FromMilliseconds(2000);
// By default, the sampling interval is set to zero, which means there is no sampling and all
// the advertisement received is returned in the Received event
// End of watcher configuration. There is no need to comment out any code beyond this point.
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
watcher.Received += OnAdvertisementReceived;
watcher.Stopped += OnAdvertisementWatcherStopped;
App.Current.Suspending += App_Suspending;
App.Current.Resuming += App_Resuming;
}
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
App.Current.Suspending -= App_Suspending;
App.Current.Resuming -= App_Resuming;
watcher.Stop();
watcher.Received -= OnAdvertisementReceived;
watcher.Stopped -= OnAdvertisementWatcherStopped;
base.OnNavigatingFrom(e);
}
private void App_Suspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e)
{
// Make sure to stop the watcher on suspend.
watcher.Stop();
// Always unregister the handlers to release the resources to prevent leaks.
watcher.Received -= OnAdvertisementReceived;
watcher.Stopped -= OnAdvertisementWatcherStopped;
}
private void App_Resuming(object sender, object e)
{
watcher.Received += OnAdvertisementReceived;
watcher.Stopped += OnAdvertisementWatcherStopped;
}
private async void OnAdvertisementReceived(BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementReceivedEventArgs eventArgs)
{
var address = eventArgs.BluetoothAddress;
BluetoothLEDevice device = await BluetoothLEDevice.FromBluetoothAddressAsync(address);
var cnt =device.GattServices.Count;
watcher.Stop();
}
/// <summary>
/// Invoked as an event handler when the watcher is stopped or aborted.
/// </summary>
/// <param name="watcher">Instance of watcher that triggered the event.</param>
/// <param name="eventArgs">Event data containing information about why the watcher stopped or aborted.</param>
private void OnAdvertisementWatcherStopped(BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementWatcherStoppedEventArgs eventArgs)
{
}
private void start_Click(object sender, RoutedEventArgs e)
{
watcher.Start();
}
}
Just a guess, but maybe you need this:
watcher.ScanningMode = BluetoothLEScanningMode.Active;
and in the OnAdvertisementReceived event
if (e.AdvertisementType == BluetoothLEAdvertisementType.ScanResponse)
{
BluetoothLEDevice blDevice = await BluetoothLEDevice.FromBluetoothAddressAsync(e.BluetoothAddress);
}
If this is a UWP project, ensure you enable Bluetooth capabilities.
To do so in Visual Studio solution explorer double click the *.appxmanifest, choose the 'Capabilities' tab and ensure that 'Bluetooth' is checked.
It will add some xml not unlike the following;
<Capabilities>
<Capability Name="internetClientServer" />
<DeviceCapability Name="bluetooth" />
</Capabilities>
This Question is over 3 years old, but because it has over 13000 views, I will answer.
The reason for Element not found is that Windows.Devices is not aware of advertising Ble-devices until they are paired or connected.
Instead in the OnAdvertisementReceived just use:
var device = await BluetoothLEDevice.FromBluetoothAddressAsync(eventArgs.BluetoothAddress);
I also have a very simple uwp example on github, it has no controls to keep it as simple as possible. All the results are shown in the debug output window.
The most usefull info is in MainPage.xaml.cs
check it out: https://github.com/GrooverFromHolland/SimpleBleExample_by_Devicename

How to put a Fez Panda II to 'Sleep' mode via button control?

I have a Fez Panda 2 with a simple switch wired into pin Di20. I have it declared as
static InputPort MySwitch = new InputPort((Cpu_Pin)FEZ_Pin.Digital.Di20, false, Port.ResistorMode.PullUp);
I have several threads in my program, one of which runs a while(true) block in which I want to use:
while(true)
{
if(MySwitch.Read()== false)
{
//put FEZ to sleep
LED.State = LED.LedState.Off; //I have an LED class to set LED on or off
}
else
{
//wake up FEZ
LED.State = LED.LedState.Off;
}
}
Any idea on how I could achieve this so that the Fez will 'hibernate' until this button is changed?
I have heard about allowing An interrupt Port, but I am unsure if this is useful/feasible in this situation. I have several COM ports connected, and want these connections to 'close' and so 'stop' all transmissions. It is due to these serial ports that it proves difficult to 'just use an interrupt port', as well I need to 'disable' the communications there (Serials are using COM1, COM3 and COM4, with regular data flowing).
Any suggestions as to how to go about this?
Low-Power-State example below taken from here:
https://www.ghielectronics.com/docs/141/low-power
using Microsoft.SPOT.Hardware;
using System;
public class Program
{
public static void Main()
{
var interrupt = new InterruptPort(Cpu.Pin.GPIO_Pin0, true, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeHigh);
interrupt.OnInterrupt += interrupt_OnInterrupt;
PowerState.Sleep(SleepLevel.DeepSleep, HardwareEvent.OEMReserved1);
///Continue on with your program here
}
private static void interrupt_OnInterrupt(uint data1, uint data2, DateTime time)
{
//Interrupted
}
}

How to play audio file in C# with low latency/very little delay in C#?

How do I play an audio file(.mp3) in C# with very little delay? What I mean is, the file should start playing the right after user input is provided and later than that.
Also, how can I play two audio files in parallel at the same time?
Take a look at the NAudio library.
For playing multiple files at the same time, see this post.
To get minimally possible delay you need audio playback running with with no/silence data and on the event of interest you will supply real playback data onto already active device. This way you eliminate overhead of activating audio playback device that might be possibly taking place. The overhead is not that large, so you might prefer to not overcomplicate your app.
There is a choice of APIs to play audio: DirectShow.NET, NAudio in particular.
Unless you are going to work with playback device in exclusive mode (which you are unlikely to want to do), all the APIs support playback of multiple independent streams and all mixing is done for you automatically behind the scene.
I show you how I do this using DirectX AudioVideoPlayback:
public class MusicPlayer
{
private static Audio m_Audio;
private static void Loop(Object Sender, EventArgs e)
{
((Audio)Sender).SeekCurrentPosition(0d, SeekPositionFlags.AbsolutePositioning);
}
public static void Dispose()
{
if (m_Audio != null)
{
m_Audio.Stop();
m_Audio.Dispose();
m_Audio = null;
}
}
public static void Mute()
{
if ((m_Audio != null) && m_Audio.Playing)
m_Audio.Volume = -10000;
}
public static void Play(String filePath, Boolean loop)
{
if (File.Exists(filePath))
{
Dispose();
if (m_Audio == null)
m_Audio = new Audio(filePath);
else
m_Audio.Open(filePath);
if (loop)
m_Audio.Ending += Loop;
m_Audio.Volume = MusicSettings.Volume - 10000;
m_Audio.Play();
}
}
public static void Unmute()
{
if (m_Audio != null)
m_Audio.Volume = MusicSettings.Value - 10000;
}
}
You can start from this snippet.

Categories