My selected characterstic property returns Indicate but still WriteClientCharacteristicConfigurationDescriptorAsync(cccdValue) does not return Success status
This is the piece of code:
status = await selectedCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(cccdValue);//writes cccd to the ble device to enable indication or notification
status = await selectedCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(cccdValue);//writes cccd to the ble device to enable indication or notification
if (status == GattCommunicationStatus.Success)
{
AddValueChangedHandler();
rootPage.NotifyUser("Successfully subscribed for value changes", NotifyType.StatusMessage);
}
else
{
rootPage.NotifyUser($"Error registering for value changes: {status}", NotifyType.ErrorMessage);
}
It always goes in else condition.I have put Indicate property True but still it does not work.
Please help, any suggestions?
Thanks
Does the characteristic support Writing?
GattCharacteristicProperties properties = characteristic.CharacteristicProperties;
if (properties.HasFlag(GattCharacteristicProperties.Write) || properties.HasFlag(GattCharacteristicProperties.WriteWithoutResponse))
{
//writing is supported..
}
If it does:
MSDN
There are four statuses:
Access Denied
Device Unreachable
Success
Protocol error
As you have not posted the status, I can't give you a precise answer... If it's Protocol Error, you need to provide more information on the device.
Try this:
Access Denied: Retry, by getting the characteristic without using the Bluetooth Cache
var characteristics = await selectedService.GetCharacteristicsForUuidAsync(characteristicUuid, BluetoothCacheMode.Uncached);
selectedCharacteristic = characteristics[0];
status = await selectedCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(cccdValue);
Then retry writing.
Device Unreachable: The connection was lost. Either the device is too far away or you need to reconnect. Recreate the device object and retry.
BluetoothLEDevice device = await BluetoothLEDevice.FromIdAsync(deviceId);
.....
One thing to be aware of, that's not well documented, is that the peripheral needs to have a writable Gatt CCCD Characteristic Descriptor with a very specific UUID (00002902-0000-1000-8000-00805f9b34fb) to be technically compliant. Android and iOS will not fail if the peripheral is non-compliant, but UWP currently will throw this exception. There does not appear to be any way to get UWP to work with a non-compliant device.
If you are making a peripheral, be aware that no matter what UUID's you use for anything, the CCCD needs be the 2902 UUID. Otherwise you'll get this UWP exception.
Related
I want to detect a connected usb device (FT232R USB UART, Virtual com port driver). This usually worked fine, but due to an windows update my device is detected as FTDI_DEVICE_UNKNOWN. Strange behaviour is, that when I first plug in my device and then start the software, everything works fine. If I first start the software and then plug in the device, it it not detected. I tried to use CyclePort to reconnect the device, but this fails with status FT_OTHER_ERROR. The device is detected and displayed in both cases in the windows device manager. Drivers were already updated and also installed manually.
Any ideas as to what is causing this?
Here is my code:
List<string> pcdSerials = new List<string>();
FTDI ftdi = new FTDI();
UInt32 ftdiDeviceCount = 0;
FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OK;
ftStatus = ftdi.GetNumberOfDevices(ref ftdiDeviceCount);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
return pcdSerials;
}
FTDI.FT_DEVICE_INFO_NODE[] ftdiDeviceList = new FTDI.FT_DEVICE_INFO_NODE[ftdiDeviceCount];
ftStatus = ftdi.GetDeviceList(ftdiDeviceList);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
return pcdSerials;
}
foreach (var info in ftdiDeviceList)
{
if (info.Type == FTDI.FT_DEVICE.FT_DEVICE_UNKNOWN)
{
if (ftdiDeviceList.Count() == 1)
{
// The effect of this function is the same as disconnecting then reconnecting the device from USB.
// Possible use of this function is in situations where a fatal error has occurred and it is difficult, or not possible, to recover without unplugging and replugging the USB cable. This function can also be used after re-programming the EEPROM to force the FTDI device to read the new EEPROM contents which previously required a physical disconnect-reconnect.
ftStatus = ftdi.CyclePort();
if (ftStatus == FTDI.FT_STATUS.FT_OK)
{
// Port has been cycled. Close the handle.
ftStatus = ftdi.Close();
}
else
{
// FT_CyclePort FAILED!
}
break;
}
}
if (info.Description != "FT232R USB UART")
continue;
if (info.Type != FTDI.FT_DEVICE.FT_DEVICE_232R)
continue;
pcdSerials.Add(info.SerialNumber);
}
return pcdSerials;
This NOT an answer, but a comment. Being new to Stack overflow it wouldn't let me simply add a comment to your question, or I don;t know what I am doing. :)
I am having what sounds like the same issue. I wrote a wrapper class over 10 years ago that has worked fine until the new FTDI driver 2.12.36.1 was updated on client's computers. FTDI released driver version 2.12.36.2 on 6/17/2021 and I was hoping that it would resolve the issue but it did not.
What I have found is that calling FT_CreateDeviceInfoList does return the correct number of devices connected. Then I call FT_GetDeviceInfoDetail to obtain the device type, description, and FTDI serial number. The device type comes back as value 0x03 which is FT_Device_Unknown and the description and serial number appear to come back empty. I use the FTDI serial number to open the device by its serial number. Without a valid serial number, I cannot open the device. I have used this method as outlined as the preferred method by FTDI for years with no issues until now.
Hopefully someone else can chime in with an answer as I have a lot of customers who are unable to connect to my product with their PCs.
I am going to reach out to FTDI support to see if they can shed some light on this problem. I will post back here if I hear something back.
I came across the same problem just recently. If you run FT_prog you can replicate this by removing the dongle and putting it back. FT_prog takes a second or so to recognise the device again.
I put the checking code in a loop with a 1 second wait and it now finds the dongle on the second attempt reliably.
I'm trying to figure out which serial port belongs to an Arduino.
Since the SerialPort class does not reveal any information about
the underlying hardware, I'm trying to use LibUsbDotNet instead.
Using the following code to get a list of all devices:
UsbDevice.ForceLibUsbWinBack = true;
var devices = UsbDevice.AllDevices;
I can then either iterate over all of them or search for the Arduino specifically:
var deviceFinder = new UsbDeviceFinder(0x2341, 0x8036);
var arduino = devices.Find(deviceFinder);
This actually works and I get an instance of UsbRegistry,
but I'm unable to open the device or determine through which serial port it is exposed.
USBDevice arduinoUsbDevice;
usbRegistry.Open(out arduinoUsbDevice);
Since this doesn't work arduinoUsbDevice remains null.
I then tried using the DeviceNotifier class which raises an event whenever
a device is added or removed from the system:
var notifier = DeviceNotifier.OpenDeviceNotifier();
notifier.OnDeviceNotify += (s, e) =>
{
WriteLine(e.Device?.Name ?? "no device");
WriteLine(e.Device?.IdProduct ?? 0);
WriteLine(e.Device?.IdVendor ?? 0);
WriteLine(e.EventType);
WriteLine(e.Object);
WriteLine(e.Port?.Name ?? "");
};
Now whenever I connect the Arduino to the computer, the event is raised twice.
As if two separate devices are being connected,
but only one of them is ever returned by UsbDevice.AllDevices:
` \\?\USB#VID_2341&PID_8036#7&533912d&0&2#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
32822
9025
DeviceArrival
FullName:USB#VID_2341&PID_8036#7&533912d&0&2#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
Vid:0x2341
Pid:0x8036
SerialNumber:7&533912d&0&2
ClassGuid:a5dcbf10-6530-11d2-901f-00c04fb951ed
no device
0
0
DeviceArrival
[Port Name:COM5]
COM5
The first time the event is raised for the device we could find before as well.
The second time it is raised with e.Device set to null but
with e.Port set to COM5, which is the information I'm after.
So the problem is I can only get this information when the Arduino is connected
after the software has been started and even then linking the two events is
kind of a guessing game.
Is there any way of getting the information without having to rely
on the events raised by the DeviceNotifier class?
I'm aware I could use System.Management and WMI queries, but
these are not available on Linux and MacOS, which is why I'm using
LibUsbDotNet instead.
The native library I'm using is libusb-1.0
As the title suggests, I want to know if there is some kind of event to catch to know when Certificate Store has changed.
The goal is to detect when a user entered a specific kind of USB smartcard / stick with a signing certificate/token in it. The certificate are registered in the Windows Cert Store, ("My", personnal certificates).
I don't like the idea of detecting USB events, because there is a variable delay between the moment when the key is plugged and the moment the certificate is actually registered (and usable).
Of course, I can always set a timer that checks the store every 10 sec or so, but I hope you'll agree that it is a not elegant solution. Of course if no other good option is available, that's what I'll end up doing I guess.
Thank you
How about a hybrid approach? Watch for USB events, then when a USB key is plugged in, start polling the store every couple of seconds until you see the new cert. Still not ideal, but much closer to it than a dumb poll every ten seconds, 24/7/365.
The trick will be knowing when the USB key is of the particular type that would end up registering a certificate. If you can know this in the USB event handler, then check for it, and if the user plugs in an ordinary flash drive, don't start polling. If you can't know this, then when you detect a new connection, you might only poll the certificate store for a minute before giving up.
I have the same problem.
I temporarily solved it by waiting until the smart card is no longer shared with another process (the Certificate Propagation Service). Not very nice and the robustness is also questionable, but it works for now.
In C#:
string selector = SmartCardReader.GetDeviceSelector();
DeviceInformationCollection devices = await DeviceInformation.FindAllAsync(selector);
foreach (DeviceInformation device in devices)
{
SmartCardReader reader = await SmartCardReader.FromIdAsync(device.Id);
reader.CardAdded += ReaderOnCardAdded;
}
private static void ReaderOnCardAdded(SmartCardReader sender, CardAddedEventArgs args)
{
Task t = ReaderOnCardAddedAsync(sender, args);
t.Wait();
}
private static async Task ReaderOnCardAddedAsync(SmartCardReader sender, CardAddedEventArgs args)
{
SmartCardProvisioning provisioning = await SmartCardProvisioning.FromSmartCardAsync(args.SmartCard);
SmartCardStatus status;
do
{
status = await provisioning.SmartCard.GetStatusAsync();
Thread.Sleep(100);
} while (status == SmartCardStatus.Shared);
PrintCertificatesOrDoSomethingElseUseful();
}
Anyone with a better solution?
I have the following code in my Windows phone 8 app.
//connection code, done during app start
socket = new StreamSocket();
await socket.ConnectAsync(serverHostName, serviceName);
dataReader = new DataReader(socket.InputStream);
dataReader.InputStreamOptions = InputStreamOptions.Partial;
dataWriter = new DataWriter(socket.OutputStream);
After the connection is established, I have another thread which checks for incoming network packets
await dataReader.LoadAsync(2048);
dataReader.ReadBytes(buffer);
----------
Workflow is as follows
Phone connects to server using socket.ConnectAsync
Server responds with initial message (Phone receives this properly in dataReader.LoadAsync function)
Phone now sends the 'business specific' request
Server now replies with 'business specific' response (Problem lies here. Phone doesn't receive the reply from server at some of the times).
There is no scenario difference between working state' and 'non working state'.
So I tried to debug this. I put a breakpoint for dataReader.LoadAsync and saw that execution waits infinitely at the call.
To make sure that the server is sending data properly, I ran the app in Windows phone emulator and ran the WireShark network analyzer in the PC. I could see that packets are being received for the IP Address of the phone.
Anyone has any hints on why the dataReader.LoadAsync function call doesn't return at all, when there is data ready to be read in the socket?
I faced the same problem. It is especially bad for Bluetooth RFCOMM SPP serial port devices, because the underlying Rfcomm-object does not provide capabilities for setting ReadTimeout values.
Edit: The InputStreamOptions.Partial option seems to be working UWP Win10 platform, but it is only useful when you are already know much data you are expecting. Otherwise it will wait indefinitely on the last call.
I almost gave up, when I found in references below these lines to solve the problem by using a CancellationTokenSource
//connect your Windows.Devices.Bluetooth.Rfcomm.RfcommDeviceService
// see the Bluetooth chat example
[...]
StreamSocket streamSocket = new StreamSocket();
await streamSocket.ConnectAsync(...); //connect to Bluetooth device
DataReader dataReader = new DataReader(inputStream); // to read from the stream
try
{
var timeoutSource = new CancellationTokenSource(1000); // 1000 ms
uint numberBytesToRead = 256;
var data = await dataReader.LoadAsync(numberBytesToRead).AsTask(timeoutSource.Token);
}
catch (TaskCanceledException)
{
// we will get here, and everything looks fine, but the problem is:
// The underlying streamSocket is also closed!
// we can not re-use the streamSocket. Any more calls to LoadAsync results in exceptions (something about the object being not assigned...)
// we need to do a full await streamSocket.ConnectAsync(...) again, but that takes ~3 seconds.
}
So this method is only a brute-force, last-resort attempt at a time-out.
The method from #mayu works very good (serialDevice.ReadTimeout), but only on devices of class Windows.Devices.SerialCommunication.Serial​Device, but not on
Windows.Devices.Bluetooth.Rfcomm.RfcommDeviceService. I don't know how the situation is for TCP/IP sockets.
In short, is there any usable time-out for RFCOMM SPP Bluetooth connections?
Or any method to know ahead of time if .LoadAsync(1) will block, because no new data is available?
This fellow over at MSDN has the exact same problem, but MS don't know an answer either: https://social.msdn.microsoft.com/Forums/vstudio/en-US/71ea17d4-ca16-43c2-ab43-02d5301def3f/chow-to-set-timeout-on-streamsocketreadasync?forum=wpdevelop
References:
In UWP StreamSocket, can I read data with timeout and leave the connection open if timeout elapses
https://social.msdn.microsoft.com/Forums/en-US/8a5c4fdc-28d6-4a22-8df6-bc519efeaa4d/how-to-control-the-timeout-for-reading-from-streamsocket?forum=winappswithcsharp
DataReader of SocketStream for UWP App
"According to documentation when using InputStreamOptions.Partial, you should use UnconsummedBufferLength instead of an hardcoded value"
That sample seems to be broken.
"await reader.LoadAsync(reader.UnconsumedBufferLength);" is equivalent to
await reader.LoadAsync(0); and then it's not possible to read any data, since you have no buffer to read from.
I'm testing this now and it seems like "reader.InputStreamOptions = Partial;" has no effect at all. My only workaround is to lower the read timeout.
According to documentation when using InputStreamOptions.Partial, you should use UnconsummedBufferLength instead of an hardcoded value :
DataReader reader = new DataReader(clientSocket.InputStream);
// Set inputstream options so that we don't have to know the data size
reader.InputStreamOptions = Partial;
await reader.LoadAsync(reader.UnconsumedBufferLength);
Sample is there
I had a similar problem using Windows Remote Arduino library and SerialUSB stream. I had to change this library and call LoadAsync(1) instead of original LoadAsync(100). Now the code is working fine.
see: https://github.com/ms-iot/remote-wiring/issues/111
For serial devices you need to set
device.ReadTimeout = TimeSpan.FromMilliseconds(100);
for the LoadAsync to return before the buffer is full.
The only way I found to get round not knowing the size of the data before reading was to read one byte at a time until I got a timeout. Feels horrid, but works. Is there a better way yet?
private async Task ReadData(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
DataReaderObject.InputStreamOptions = InputStreamOptions.Partial;
uint data = 0;
uint bufferLength = DataReaderObject.UnconsumedBufferLength;
var timeoutSource = new CancellationTokenSource(100); // 100 ms
try
{
while (true)
{
data = await DataReaderObject.LoadAsync(1).AsTask(timeoutSource.Token);
if (data > 0)
{
String temp = DataReaderObject.ReadString(data);
TemperatureValue.Text += temp.Trim();
}
}
}
catch (Exception)
{
;
}
}
I am currently working on a WinForm app to stream videos from IP camera using the RTSP protocol in C#. Everything worked fine. Part of the requirement for the app includes a function to check whether the IP camera is online or not.
So I did a ping function using the System.Net.NetworkInformation.Ping class to ping the IP camera. Say if the RTSP url of the camera is as follows rtsp://[CAMERA IP]:554/Master0-RTSP/1.0, I would only need to extract the [CAMERA IP] part and use the Ping class to see if the camera is online or not by using its IP.
Initially, it works until an issue came, say if one to enter an IP which may not be the intended IP Camera (say an IP of a computer) the ping function would still work if the entered IP of the entered device is online.
I tried to search for something like a RTSP ping but could not find one. Was hoping for any advices or opinions on this matter. Any example in C# are greatly appreciated. Thank you for your kind attention.
OPTIONS can possibly work but the standard specifies the correct way is through using theGET_PARAMETER.
RFC2326 outlines that clearly
http://www.ietf.org/rfc/rfc2326.txt
10.8 GET_PARAMETER
The GET_PARAMETER request retrieves the value of a parameter of a
presentation or stream specified in the URI. The content of the reply
and response is left to the implementation. GET_PARAMETER with no
entity body may be used to test client or server liveness ("ping").
While GET_PARAMETER may not be supported by the server there is no way to tell how that server will react to the OPTIONS request which does not even require a sessionID. Therefor it cannot be guaranteed it will keep your existing session alive.
This is clear from reading the same RFC about the OPTIONS request
10.1 OPTIONS
The behavior is equivalent to that described in [H9.2]. An OPTIONS
request may be issued at any time, e.g., if the client is about to
try a nonstandard request. It does not influence server state.
Example:
C->S: OPTIONS * RTSP/1.0
CSeq: 1
Require: implicit-play
Proxy-Require: gzipped-messages
S->C: RTSP/1.0 200 OK
CSeq: 1
Public: DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE
Note that these are necessarily fictional features (one would hope
that we would not purposefully overlook a truly useful feature just
so that we could have a strong example in this section).
If GET_PARAMETER is not supported then you would issue a PLAY request with the SessionId of the session you want to keep alive.
This should work even if OPTIONS doesn't as PLAY honors the Session ID and if you are already playing there is no adverse effect.
For the C# RtspClient see my project # https://net7mma.codeplex.com/
And the article on CodeProject # http://www.codeproject.com/Articles/507218/Managed-Media-Aggregation-using-Rtsp-and-Rtp
Regarding RTSP in C# see this thread Using RTMP or RTSP protocol in C#
Regarding Ping ... you can implement is as DESCRIBE operation ... but pay attention do not make it too frequently, the device should be affected.
http://www.ietf.org/rfc/rfc2326.txt
Instead of ICMP ping, you might want to keep a helper RTSP session without video/audio RTP streams, checking good standing of socket connection and sending OPTIONS or DESCRIBE command on a regular basis, e.g. once a minute, in order to see if the device is responsive.
Some suggest using GET_PARAMETER instead of options, however this is inferior method. OPTIONS is mandatory, GET_PARAMETER is not. Both serve different purpose. Both have small server side execution expense. OPTIONS is clearly the better of the two.
Some servers may not support setting stream parameters and thus not support GET_PARAMETER and SET_PARAMETER.
You can use RTSPClientSharp and do something like this:
public static async Task TestRTSPConnection(string rtspAddress, string user, string password)
{
var serverUri = new Uri(rtspAddress);
var credentials = new NetworkCredential(user, password);
var connectionParameters = new ConnectionParameters(serverUri, credentials);
var cancellationTokenSource = new CancellationTokenSource();
var connectTask = ConnectAsync(connectionParameters, cancellationTokenSource.Token);
if (await Task.WhenAny(connectTask, Task.Delay(15000 /*timeout*/)) == connectTask)
{
if (!connectTask.Result)
{
logger.Warn("Connection refused - check username and password");
}
logger.Info("Connection test completed");
}
else
{
logger.Warn("Connection timed out - check username and password");
}
}
private static async Task<bool> ConnectAsync(ConnectionParameters connectionParameters, CancellationToken token)
{
try
{
using (var rtspClient = new RtspClient(connectionParameters))
{
rtspClient.FrameReceived +=
(sender, frame) => logger.Info($"New frame {frame.Timestamp}: {frame.GetType().Name}");
while (true)
{
logger.Info("Connecting...");
try
{
await rtspClient.ConnectAsync(token);
}
catch (OperationCanceledException)
{
logger.Info("Finishing test before connection could be established. Check credentials");
return false;
}
catch (RtspClientException e)
{
logger.Error($"{e.Message}: {e.InnerException?.Message}");
return false;
}
logger.Info("Connected - camera is online");
return true;
}
}
}
catch (OperationCanceledException)
{
return false;
}
}
It works for me pretty well if you just care about pinging and if the camera is online or not. Also timeout happens when credentials are incorrect. You get direct failure if port is not exposed or connection is refused.