How one forces Windows to disconnect from BLE device being used in UWP app? I receive notifications from some characteristics but at some point I want to stop receiving them and make sure I disconnect from the BLE device to save BLE device's battery?
Assuming your application is running as a gatt client and you have the following instances your are working with in your code:
GattCharacteristic myGattchar; // The gatt characteristic you are reading or writing on your BLE peripheral
GattDeviceService myGattServ; // The BLE peripheral' gatt service on which you are connecting from your application
BluetoothLEDevice myBleDev; // The BLE peripheral device your are connecting to from your application
When you are already connected to your BLE peripheral, if you call the Dispose() methods like this :
myBleDev.Dispose(); and/or myGattServ.Dispose(); and/or myGattchar.Service.Dispose()
you surely will free resources in your app but will not cleanly close the BLE connection: The application looses access to control resources for the connection. Nevertheless, connection remains established on the lower levels of the stack (On my peripheral device the Bluetooth connection active LED remains ON after calling any of Dispose() methods).
Forcing disconnection is done by first disabling notifications and indications on the concerned characteristic (i.e. myGattchar in my example above) by writing a 0 (zero) to the Client Characteristic Configuration descriptor for that characteristic through call to method WriteClientCharacteristicConfigurationDescriptorAsync with parameter GattClientCharacteristicConfigurationDescriptorValue.None :
GattCommunicationStatus status =
await myGattchar.WriteClientCharacteristicConfigurationDescriptorAsync(
GattClientCharacteristicConfigurationDescriptorValue.None);
Just dispose all objects related to the device. That will disconnect the device, unless there are other apps connected to it.
For my UWP app, even though I've used Dispose() methods, I still received notifications. What helped me was setting my device and characteristics to null. Example:
device.Dispose();
device = null;
Not all to certain of how "correct" this programming is, but it's been working fine for me so far.
The UWP Bluetooth BLE sample code from Microsoft (dispose the BLE device) didn't work for me. I had to add code (dispose the service) to disconnect the device.
private async Task<bool> ClearBluetoothLEDeviceAsync()
{
if (subscribedForNotifications)
{
// Need to clear the CCCD from the remote device so we stop receiving notifications
var result = await registeredCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.None);
if (result != GattCommunicationStatus.Success)
{
return false;
}
else
{
selectedCharacteristic.ValueChanged -= Characteristic_ValueChanged;
subscribedForNotifications = false;
}
}
selectedService?.Dispose(); //added code
selectedService = null; //added code
bluetoothLeDevice?.Dispose();
bluetoothLeDevice = null;
return true;
}
Remember you must call -= for events you have called += or Dispose() will never really garbage collect correctly. It's a little more code, I know. But it's the way it is.
Not just with bluetooth stuff, I will remind you - with everything. You can't have hard referenced event handlers and get garbage collection to work as expected.
Doing all the disposing and null references suggested didn't achieve the Windows (Windows Settings) disconnection I was looking for.
But dealing with IOCTL through DeviceIoControl did the job.
I found that after calling GattDeviceService.GetCharacteristicsAsync(), BluetoothLeDevice.Dispose() does not work. So I dispose the Service I don't need.
GattCharacteristicsResult characteristicsResult = await service.GetCharacteristicsAsync();
if (characteristicsResult.Status == GattCommunicationStatus.Success)
{
foreach (GattCharacteristic characteristic in characteristicsResult.Characteristics)
{
if (characteristic.Uuid.Equals(writeGuid))
{
write = characteristic;
}
if (characteristic.Uuid.Equals(notifyGuid))
{
notify = characteristic;
}
}
if (write == null && notify == null)
{
service.Dispose();
Log($"Dispose service: {service.Uuid}");
}
else
{
break;
}
}
Finally, when I want to disconnect the Bluetooth connection
write.Service.Dispose();
device.Dispose();
device = null;
Related
Im using C# AsterNET to manage my Asterisk commands and events, and now I do have a new feature to work on.
This is simple (I think) but I'm stucked right now.
Scenario
I do have two queues, 8100 and 8300, and 2 extensions being 8101 and 8301. When I do have a call from PSTN it is driven to 8100 queue. When the 8101 extension become available I do add this extension to the 8100 queue, so the calling PSTN device will be redirected to this 8101 extension.
Everything is working fine till here.
Sometimes I do park the calling device and let 8301 knows it using my app, so 8301 user using the same app can send a command asking for that parked channel to be redirect to his SIP Phone. Also working fine.
Scope
Now I want to have some feature to let 8101 transfer this calling device to my other queue, the 8300. So I just tried to reuse my parked method and redirect method
internal void Park(string channel, int parkTimeout)
{
ParkAction pa = new ParkAction(channel, channel, parkTimeout.ToString());
ManagerResponse mr = manager.SendAction(pa);
}
internal void RedirectFromParking(string channel, string exten)
{
RedirectAction ra = new RedirectAction
{
Priority = 1,
Context = "default",
Channel = channel,
Exten = exten
};
ManagerResponse mr = manager.SendAction(ra);
}
Park("abc123456", 10000);
RedirectFromParking("abc123456", "8300")
Issue
I'm parking fine but when I try to redirect from parking to my queue the calling device is just disconnected and the connection is lost.
How can I transfer a parked call to my queue or transfer it directly to the queue (would be better) without needing to originate?
Just do hold instead of parking and make your own list of such calls.
To transfer to a queue I can do a blind transfer as documented on Asterisk website. Links below:
ManagerAction_BlindTransfer
ManagerEvent_BlindTransfer
To achieve this using AsterNET, I can use the same RedirectAction I was using but I do need to change the context. It can't be default for context, as default we are letting Asterisk manage it and somehow it can't handle as I expetected. So it need to be clearly specified as internar transfer. The event raised after this context transfer is the Manager_BlindTransfer.
Manager_Action_RedirectAction
So using my SIP Phone I manage to transfer a call while I was debugging that raised event method, so I could catch the context used in. Using the correct context
ManagerConnection manager = new ManagerConnection(address, port, user, password);
manager.BlindTransfer += Manager_BlindTransfer;
private void Manager_BlindTransfer(object sender, BlindTransferEvent e)
{
}
After this I created another method to transfer to directly to a queue using the correct context.
internal void TransferToQueue(string channel, string queue)
{
RedirectAction ma = new RedirectAction
{
Priority = priority,
Context = "from-internal-xfer",
Channel = channel,
Exten = queue
};
ManagerResponse mr = manager.SendAction(ma);
}
TransferToQueue("abc123456", "8300")
Summary
Was just a matter of the correct context to be used in.
from-internal-xfer
I am new to win32 api progamming, and I am tring writing a xmpp client for windows platform, using win32 api and gloox xmpp library. gloox has its own event loop, while windows GUI has message loop too. I am not very clear how to use these two loops together.
From the gloox document:
Blocking vs. Non-blocking Connections
For some kind of bots a blocking connection (the default behaviour) is ideal. All the bot does is react to events coming from the server. However, for end user clients or anything with a GUI this is far from perfect.
In these cases non-blocking connections can be used. If ClientBase::connect( false ) is called, the function returnes immediately after the connection has been established. It is then the resposibility of the programmer to initiate receiving of data from the socket.
The easiest way is to call ClientBase::recv() periodically with the desired timeout (in microseconds) as parameter. The default value of -1 means the call blocks until any data was received, which is then parsed automatically.
Window message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
Window proc:
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
TCHAR str[100];
StringCbPrintf(str, _countof(str), TEXT("Message ID:%-6x:%s"), msg, GetStringMessage(msg));
OutputDebugString(str);
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
switch (msg)
{
case WM_CREATE:
return 0;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &rect);
DrawText(hdc, TEXT("DRAW TEXT ON CLIENT AREA"), -1, &rect, DT_CENTER | DT_SINGLELINE | DT_VCENTER);
EndPaint(hWnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
gloox blocking connection
JID jid( "jid#server/resource" );
Client* client = new Client( jid, "password" );
client->registerConnectionListener( this );
client->registerPresenceHandler( this );
client->connect();// here will enter event loop
gloox non-blocking connection
Client* client = new Client( ... );
ConnectionTCPClient* conn = new ConnectionTCPClient( client, client->logInstance(), server, port );
client->setConnectionImpl( conn );
client->connect( false );
int sock = conn->socket();
[...]
I am not very clear how can I
call ClientBase::recv() periodically with the desired timeout (in microseconds) as parameter
With a timer ? or multi thread programming ? or there is a better solution ?
Any suggestions appreciated
Thank you
The best IO strategy for that is overlapped IO. Unfortunately, the method is windows only, not supported by the cross-platform library you’ve picked.
You can use SetTimer() API, and periodically call recv() method of the library with zero timeout, in WM_TIMER handler. This will introduce extra latency (your PC receives a message but it has to wait for the next timer event to handle it), or if you’ll use small intervals like 20 ms, will consume battery on laptops or tablets.
You can use blocking API with a separate thread. More efficient performance-wise, but harder to implement, you’ll have to marshal messages and other events to the GUI thread. WM_USER+n custom windows messages is usually the best way to do that, BTW.
I'm implementing a Thrift client in order to make connection to a built-in scribe server.
Everything is going OK if I use a standard Log method, like this:
public boolean log(List<LogEntry> messages) {
boolean ret = false;
PooledClient client = borrowClient();
try {
if ((client != null) && (client.getClient() != null)) {
ResultCode result = client.getClient().Log(messages);
ret = (result != null && result.equals(ResultCode.OK));
returnClient(client);
}
} catch (Exception ex) {
logger.error(LogUtil.stackTrace(ex));
invalidClient(client);
}
return ret;
}
However, when I use send_Log instead:
public void send_Log(List<LogEntry> messages) {
PooledClient client = borrowClient();
try {
if ((client != null) && (client.getClient() != null)) {
client.getClient().send_Log(messages);
returnClient(client);
}
} catch (Exception ex) {
logger.error(LogUtil.stackTrace(ex));
invalidClient(client);
}
}
It acctually causes some problems:
Total network connection to port 1463 (default port for a scribe server) is going to increase so much, and always in a CLOSE_WAIT state.
Cause my application got stuck without throwing any error, I think it may be an issue with network connection.
what if send without recv
As this is clearly TCP, the sender will block (in blocking mode), or incur EAGAIN/EWOULDBLOCK in non-blocking mode. EDIT It is now clear that you want to send without receiving the reply. You can do that by just sending and then closing the socket, but that may cause the peer to incur ECONNRESET, which may upset it. You should really implement the application protocol correctly.
1/ Total network connection to port 1463 (default port for a scribe server) is going to increase so much, and always in a CLOSE_WAIT state.
Lots of ports in CLOSE_WAIT state indicates a socket leak on the part of the local application.
2/ Cause my application got stuck without throwing any error. I think it may be an issues with network connection.
It is an issue with sending and not receiving.
Since you labelled this as a Thrift related question, the answer is oneway.
service foo {
oneway void FireAndForget(1: some args)
}
The oneway keyword does exactly what the name suggests. You get a client implementation that only sends and does not wait for anything to be returned from the server. This rule also includes exceptions. Hence a oneway method must always be void and can't throw any exceptions.
However, when I use send_Log instead ...
client.getClient().send_Log(messages);
Neither one of the Thrift-generated send_Xxx and recv_Xxx methods are meant to be public. That's why they are usually either private or protected methods. They should not be called directly, unless you are sure that you know what you are doing (and very obviously the latter is not the case here).
And since the real question is about performance: Why don't you just delegate the call(s) into a secondary thread? That way the I/O will not block the UI.
I'm currently working with an Arduino trying to build an ad hoc network to which a device can connect to and send web requests to. The problem I am currently having is that I can only set up one connection and then when that connection is terminated (with client.stop()), all subsequent connections are not picked up by the server, even a cURL command just sits there spinning. The first connection I start when I reset the server works fine, and I am able to talk to the server; but after that, the Arduino can no longer find new clients (even though it's trying with the library given).
I`m using the SparkFun library for the WiFly shield cloned from GitHub, along with an Arduino Uno.
My current code is based off their default example 'WiFly_AdHoc_Example', but I had to remove a few things to get the network to start up which might be the cause of this problem.
Here is the .ino file that I am running.
#include <SPI.h>
#include <WiFly.h>
//#include <SoftwareSerial.h>
//SoftwareSerial mySerial( 5, 4); //Part from example not used (see below)
WiFlyServer server(80); //Use telnet port instead, if debugging with telnet
void setup()
{
Serial.begin(9600);
//The code below is from the example, but when I run it the WiFly will hang
// on Wifly.begin(). Without it, the WiFly starts up fine.
//mySerial.begin(9600);
//WiFly.setUart(&mySerial); // Tell the WiFly library that we are not
// using the SPIUart
Serial.println("**************Starting WiFly**************");
// Enable Adhoc mod
WiFly.begin(true);
Serial.println("WiFly started, creating network.");
if (!WiFly.createAdHocNetwork("wifly"))
{
Serial.print("Failed to create ad hoc network.");
while (1)
{
// Hang on failure.
}
}
Serial.println("Network created");
Serial.print("IP: ");
Serial.println(WiFly.ip());
Serial.println("Starting Server...");
server.begin();
Serial.print("Server started, waiting for client.");
}
void loop()
{
delay(200);
WiFlyClient client = server.available();
if (client)
{
Serial.println("Client Found.");
// A string to store received commands
String current_command = "";
while (client.connected())
{
if (client.available())
{
//Gets a character from the sent request.
char c = client.read();
if (c=='#' || c=='\n') //End of extraneous output
{
current_command = "";
}
else if(c!= '\n')
{
current_command+=c;
}
if (current_command== "get")
{
// output the value of each analog input pin
for (int i = 0; i < 6; i++)
{
client.print("analog input ");
client.print(i);
client.print(" is ");
client.print(analogRead(i));
client.println("<br />");
}
}
else if(current_command== "hello")
{
client.println("Hello there, I'm still here.");
}
else if (current_command== "quit")
{
client.println("Goodbye...");
client.stop();
current_command == "";
break;
}
else if (current_command == "*OPEN*")
{
current_command == "";
}
}
}
// Give the web browser time to receive the data
delay(200);
// close the connection
client.stop();
}
}
This script is just a mini protocol I set up to test. Once connected with the wifly module you can send text such as "get" "hello" or "quit" and the wifly module should respond back.
Using Telnet I can successfully connect (the first time) and send commands to the Arduino including "quit" to terminate the connection (calls the client.stop() method). But when I try to reconnect though Telnet, it says the connection was successful, but on the Arduino it's still looping thinking the client is still false. What??
I know right, I'm getting mixed messages from Telnet vs Arduino. None of the commands work obviously since the Ardunio is still looping waiting for a client that evaluates to true. I'm going to take a look at WiFlyServer from the library I imported and see if I can dig up the problem, because somehow that server.available() method isn't finding new clients.
I am noticing a lot of TODO's in the library code....
So I found the reason for the problem. It was in the WiFlyServer.cpp file from the SparkFun library. The code that was causing the reconnect issue was in fact the server.availible() method. Right at the top of the method, there is a check:
// TODO: Ensure no active non-server client connection.
if (!WiFly.serverConnectionActive) {
activeClient._port = 0;
}
For some reason when I comment this out, I can connect and reconnect perfectly fine and everything works as it should. I will now dive into the library and see if I can fix this, I'm not exactly sure what this is doing, but it gets called when the server connection is not active and is somehow blocking subsequent connections. The problem with this solution is that the Arduino always thinks it has found a client since client and client.connected() evaluate to true even if one doesn't exist. Even client.available() evaluates to true right when the connection is terminated and the ghost "client" is found, but after that first run through the if-statement the ghost "client" is no longer available(). Even with this flaw it still picks up a new client when it comes along which is why it works.
How might I get to the root of this problem without using this commenting hack?
Are their any risks or future problems I might run into doing it this way?
What is the purpose of the block that I commented out in the first place?
Well, when you're calling client.stop(); how does the Arduino know whether the client has to start again?
Remember setup() executes only once.
Have you tried to include the following code in your loop to tell the Arduino to create the WiFly AdHoc network again? This may or may not work. I don't have one myself and haven't played with the Wifly shield but it's worth a try.
Remember to only ever execute the code once every time you need to connect again since it's sitting inside a loop that's always going to be running.
WiFly.begin(true);
Serial.println("WiFly started, creating network.");
if (!WiFly.createAdHocNetwork("wifly"))
{
Serial.print("Failed to create ad hoc network.");
while (1)
{
// Hang on failure.
}
}
I have a simple sketch on my Seeeduino Mega 1.22 which just displays the serial input on a LCD Display. Using lynx term and the arduino serial monitor works fine: sent input is being displayed. The trouble starts when I want to start serial communication between my Java programm, running in Eclipse on a Win7 x64 machine, and the Seeeduino. I'm using the RXTX x64 build. The programm is intended to send and receive some string.getBytes() via the open port. Receiving on the Java side works, but receiving on the Arduino side fails.
It seems that the problem is the proper Flow Control setting. I saw that some people had the same issue like here Issues receving in RXTX
But this solution does not work for me. If I set the FlowControl to None, than I get only a block icon on the display, indicating, that the serial connection has been established, but nothing else. If I set the FlowControl to RCTS_IN | RCTS_OUT, then I get the string bytes only on the display when I close the established connection.
Why is the data only send when I close the connection (Flushing the out stream did not help as well) ? What am I doing wrong with the Flow Controll settings?
This is the modified connect() method I'm using.
void connect(String portName) throws Exception {
CommPortIdentifier portIdentifier = CommPortIdentifier
.getPortIdentifier(portName);
if (portIdentifier.isCurrentlyOwned()) {
System.out.println("Error: Port is currently in use");
} else {
CommPort commPort = portIdentifier.open(this.getClass().getName(),
2000);
if (commPort instanceof SerialPort) {
SerialPort serialPort = (SerialPort) commPort;
serialPort.setSerialPortParams(115200, SerialPort.DATABITS_8,
SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
try {
serialPort.setFlowControlMode(
// SerialPort.FLOWCONTROL_NONE);
// OR
// If CTS/RTS is needed
//serialPort.setFlowControlMode(
SerialPort.FLOWCONTROL_RTSCTS_IN |
SerialPort.FLOWCONTROL_RTSCTS_OUT);
} catch (UnsupportedCommOperationException ex) {
System.err.println(ex.getMessage());
}
serialPort.setRTS(true);
in = serialPort.getInputStream();
out = serialPort.getOutputStream();
(new Thread(new SerialWriter(out))).start();
serialPort.addEventListener(new SerialReader(in, this));
serialPort.notifyOnDataAvailable(true);
} else {
System.out.println("Error: Only serial ports are to use!");
}
}
}
Thanks in advance for your time
Solved it. It was not the buffer, as many suggested it. The problem was, that the Seeeduinos RST Switch on the board was set to automatic. Setting it to manual, solved the problem.
No Flow-Controll needed.