How to check if BLE advertisement is already enabled (HCI) - bluetooth

BLE advertising can be enabled using HCI_LE_Set_Advertising_Enable[1] command which returns status 0x00 if HCI_LE_Set_Advertising_Enable command succeeded or status code 0x01 to 0xFF[2] if the command failed.
If the advertisement is already enabled (e.g. calling this command for the second time with Advertising_Enable parameter set to 0x01) then this or HCI_LE_Set_Advertising_Data commands will return status 0x0C (Command Disallowed).
There are (at least) two problems with this:
Enabling advertising when it is already enabled can cause the random
address to change. Disabling advertising when it is already disabled
has no effect. [1]
BlueZ stack contains the following piece of code at the end of most HCI library functions:
if (status) {
errno = EIO;
return -1;
}
which causes e.g. hci_le_set_advertise_enable function to return generic fail code -1 and set errno to EIO, which is indistinguishable from any other BlueZ error, HCI error or an actual IO error (HCI layer uses UART).
How to check if the LE advertisement is already enabled to be able to perform safe/strict error handling? I cannot find any command for Get Advertising Status in the BT Core Specs. I cannot rely on something like
if ((rc == -1) && (errno == EIO)) {
/* Actually OK, advertising is already enabled */
return 0;
}
Thank you.
References:
[1] BT CS 5.2 [Vol 4] Part E, Section 7.8.9
[2] BT CS 5.2 [Vol 1] Part F, Controller Error Codes

The idea is that the Bluetooth stack on the host side should know if it has started advertising or not. That's how it should work. If you manually bypass the Bluetooth stack on the host side (which you shouldn't do unless you are debugging or something), sending your own hci command, then you can't know.

Related

AOSP Pie bluetooth HCI not hanging: hci_initialize error

I have a test board for amlogic S905X chip. (p212 reference board) When I burn my ROM into it, the bluetooth constantly shows "stopping" dialog.
The logfile (tombstone) is quite long but the important part is here:
01-01 00:24:15.708 28953 28986 I bt_hci : hci_initialize
01-01 00:24:15.710 28953 28970 D bt_hci : hci_module_start_up starting async portion
01-01 00:24:15.711 28953 28986 I bt_hci : hci_initialize: IBluetoothHci::getService() returned 0xa1b91560 (remote)
01-01 00:24:16.209 28953 28987 F : [0101/002416.209517:FATAL:hci_layer_android.cc(78)] Check failed: status == Status::SUCCESS.
It seems the hardware is initialized but the the HCI can not be started. Is it related to kernel drivers or android user space and HAL modules? or even framework(?!)
How can I approach this problem to solve it?
the full tombstone log file is pasted here
Thanks
EDIT :
logcat is pasted here.
Your tombstone tells you that your process terminated because the assertion CHECK(status == Status::SUCCESS) failed in hci_layer_android.cc:78.
That problem goes back to the Bluetooth HAL calling initializationComplete(Status::INITIALIZATION_ERROR).
You have to check your Bluetooth HAL implementation for how this can happen.
Checking logcat for messages from android.hardware.bluetooth#1.0-impl could help.
The reasons for a failure and the corresponding log messages from the default bluetooth HAL implementation can be found here.

D-Bus connection error after Bluez 5.50 Gatt Server termination

I am running a BlueZ Gatt server based upon BlueZ V5.50 and the example-gatt-server.py file contained in the BlueZ test directory. Many times when the server program exits/terminates the D-Bus is left in an unstable condition and I cannot successfully execute the program again without rebooting.
The error message received follows. This error persists until the system is rebooted.
('adapter (val/add) = ', dbus.ObjectPath('/org/bluez/hci0/dev_62_D9_BD_2F_9D_DB/service0018/char0019/desc001b'), '/', '0x75e2a020')
('service_manager (val/loc) = ', <Interface <ProxyObject wrapping <dbus._dbus.SystemBus (system) at 0x75dbbea0> :1.7 /org/bluez/hci0/dev_62_D9_BD_2F_9D_DB/service0018/char0019/desc001b at 0x75e5bf90> implementing 'org.bluez.GattManager1' at 0x75db9f70>, '/', '0x75e168a0')
ERROR:dbus.connection:Unable to set arguments (dbus.ObjectPath('/'), {}) according to signature None: <type 'exceptions.ValueError'>: Unable to guess signature from an empty dict
Resting bluetooth adapter power off/on has no effect
The error occurs asynchronous to the program so pdb has not helped
System information:
GNU/Lunix 4.19.42-v7 #1219
Bluez 5.50 with experimental flag set

USB Serial port programming has "disastrous" results

I am currently working on a C program running on a Raspberry Pi 3 (Linux Ubuntu) that is intended to provide a web page interface for configuring networking on an embedded system.
The code is being developed using Code::Blocks with the GDB debugger. I'm using microhttpd for the web server and that, plus the various web pages, are all working great. I'm now working on the USB Serial link to the embedded system using information in "Serial Programming Guide for POSIX Operating Systems".
The code below is responsible for opening the USB Serial link to the target system and seems to work fine - once. If I close the program and restart it (either standalone on the command line or from within Code::Blocks) the second time microhttpd is hosed - browser windows will no longer connect. Further, from within Code::Blocks the debugger is also hosed - once the program is started it cannot be paused or stopped. The only way is to kill it by closing the project.
The problem is clearly within the function since I can comment out the call to it and everything works as it did previously. Unfortunately, once the problem happens the only solution seems to be to reboot the Pi.
I've done things like this before using a scripting language (Tcl) but this time around I'm looking for a performance boost from a non-interpreted language since the Pi will also be running a high bandwidth data logging program through a similar USB serial interface.
The code is shown below:
/******************************************************************************/
/* This function scans through the list of USB Serial ports and tries to */
/* establish communication with the target system. */
/******************************************************************************/
void tapCommInit(void) {
char line[128];
char port[15]; // this is always of the form "/dev/TTYACMn"
char *ptr;
FILE *ifd;
struct termios options;
uint8_t msgOut[3], msgIn[4];
msgOut[0] = REQ_ID; // now prepare the message to send
msgOut[1] = 0; // no data so length is zero
msgOut[2] = 0;
/**************************************************************************/
/* First, get the list of USB Serial ports. */
/**************************************************************************/
system("ls -l /dev/serial/by-path > usbSerial\n"); // get current port list
ifd = fopen("usbSerial", "r");
logIt(fprintf(lfd, "serial ports: \n"));
/**************************************************************************/
/* The main loop iterates through the file looking for lines containing */
/* "tty" which should be a valid USB Serial port. The port is configured */
/* in raw mode as 8N1 and an ID request command is sent, which has no */
/* data. If a response is received it's checked to see if the returned */
/* ID is a match. If not, the port is closed and we keep looking. If a */
/* match is found, tapState is set to "UP" and the function returns. If */
/* no match is found, tapState is left in the initial "DOWN" state. */
/**************************************************************************/
while(1) {
if (fgets(line, 127, ifd) == NULL) { // end of file?
break; // yes - break out and return
}
ptr = strstr(line, "tty"); // make sure the line contains a valid entry
if (ptr == NULL) {
continue; // nothing to process on this line
}
strcpy(port, "/dev/"); // create a correct pathname
strcat(port, ptr); // append the "ttyACMn" part of the line
port[strlen(port)-1] = 0; // the last character is a newline - remove it
logIt(fprintf(lfd," %s\n", port)); // we have a port to process now
cfd = open(port, O_RDWR | O_NOCTTY | O_NDELAY); // cfd is a global int
if (cfd == -1) {
logIt(fprintf(lfd, "Could not open port: %s\n", port));
continue; // keep going with the next one (if any)
}
fcntl(cfd, F_SETFL, 0); // blocking mode
tcgetattr(cfd, &options); // get the current port settings
options.c_cflag |= (CLOCAL | CREAD); // ena receiver, ignore modem lines
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // raw, no echo
options.c_oflag &= ~OPOST; // no special output processing
options.c_cc[VMIN] = 0; // minimum number of raw read characters
options.c_cc[VTIME] = 10; // timeout in deciseconds (1 second timeout)
tcsetattr(cfd, TCSANOW, &options); // set options right now
cfsetispeed(&options, B115200); // input baud rate
cfsetospeed(&options, B115200); // output baud rate
options.c_cflag &= ~(CSIZE | PARENB | // clear size bits, no parity
CSTOPB | CRTSCTS); // 1 stop bit, no hw flow control
options.c_cflag |= CS8; // now set size: 8-bit characters
options.c_cflag &= ~(IXON | IXOFF | IXANY); // no sw flow control
if (write(cfd, msgOut, 3) < 3) {
logIt(fprintf(lfd, "Sending of output message failed\n"));
close(cfd);
continue;
}
if (read(cfd, msgIn, 4) != 4) {
logIt(fprintf(lfd, "Didn't get expected amount of return data\n"));
close(cfd);
continue;
}
if (msgIn[3] != HOST_ID) {
logIt(fprintf(lfd, "Got the wrong HOST_ID response\n"));
close(cfd);
continue;
}
logIt(fprintf(lfd, "Port found - communication established\n"));
tapState = UP;
break; // we're done - break out of the loop
}
fclose(ifd); // close and remove the file we created
remove("usbSerial");
}
from within Code::Blocks the debugger is also hosed - once the program is started it cannot be paused or stopped
It is far more likely that you do not understand your tools than that you have created an unkillable program.
It's easy enough to figure this out: divide and conquer. You've got a whole pile of unrelated components here. Start separating them and find out which pieces work fine in isolation and which continue to behave badly when disconnected from everything else. Then you'll have your culprit.
Specifically here, that means try running your program outside the IDE, then under command line gdb instead of GDB via the IDE.
Also, it should be possible to run your program without starting the web server piece, so that you can run the serial part of the app in isolation. This is not only good for debugging by minimizing confounding variables, it also encourages a loosely-coupled program design, which is a good thing in its own right.
In the end, you may find that the thing keeping your program from stopping is the web framework, Code::Blocks, or the way GDB operates on the Pi under Code::Blocks, rather than anything to do with the USB to serial adapter.
once the problem happens the only solution seems to be to reboot the Pi
If your program is still running in the background, then of course your next instance will fail if it tries to open the same USB port.
Don't guess, find out:
$ sudo lsof | grep ttyACM
or:
$ lsof -p $(pidof myprogram)
(Substitute pgrep if your system doesn't have pidof.)
I've done things like this before using a scripting language (Tcl) but this time around I'm looking for a performance boost from a non-interpreted language
Your serial port is running at 115,200 bps. Divide that by 10 to account for the stop and start bits, then flip the fraction to get seconds per byte, and you come to 87 microseconds per byte. And you only achieve that when the serial port is running flat-out, sending or receiving 11,500 bytes per second. Wanna take a guess at how many lines of code Tcl can interpret in 87 microseconds? Tcl isn't super-fast, but 87 microseconds is an eternity even in Tcl land.
Then on the other side of the connection, you have HTTP and a [W]LAN, likely adding another hundred milliseconds or so of delay per transaction.
Your need for speed is an illusion.
Now come back and talk to me again when you need to talk to 100 of these asynchronously, and then maybe we can start to justify C over Tcl.
(And I say this as one whose day job involves maintaining a large C++ program that does a lot of serial and network I/O.)
Now lets get to the many problems with this code:
system("ls -l /dev/serial/by-path > usbSerial\n"); // get current port list
ifd = fopen("usbSerial", "r");
Don't use a temporary where a pipe will suffice; use popen() here instead.
while(1) {
This is simply wrong. Say while (!feof(ifd)) { here, else you will attempt to read past the end of the file.
This, plus the next error, is likely the key to your major symptoms.
if (fgets(line, 127, ifd) == NULL) {
break;
There are several problems here:
You're assuming things about the meaning of the return value that do not follow from the documentation. The Linux fopen(3) man page isn't super clear on this; the BSD version is better:
The fgets() and gets() functions do not distinguish between end-of-file and error, and callers must use feof(3) and ferror(3) to determine which occurred.
Because fgets() is Standard C, and not Linux- or BSD-specific, it is generally safe to consult other systems' manual pages. Even better, consult a good generic C reference, such as Harbison & Steele. (I found that much more useful than K&R back when I was doing more pure C than C++.)
Bottom line, simply checking for NULL doesn't tell you everything you need to know here.
Secondarily, the hard-coded 127 constant is a code bomb waiting to go off, should you ever shrink the size of the line buffer. Say sizeof(line) here.
(No, not sizeof(line) - 1: fgets() leaves space for the trailing null character when reading. Again, RTFM carefully.)
The break is also a problem, but we'll have to get further down in the code to see why.
Moving on:
strcat(port, ptr); // append the "ttyACMn" part of the line
Two problems here:
You're blindly assuming that strlen(ptr) <= sizeof(port) - 6. Use strncat(3) instead.
(The prior line's strcpy() (as opposed to strncpy()) is justifiable because you're copying a string literal, so you can see that you're not overrunning the buffer, but you should get into the habit of pretending that the old C string functions that don't check lengths don't even exist. Some compilers will actually issue warnings when you use them, if you crank the warning level up.)
Or, better, give up on C strings, and start using std::string. I can see that you're trying to stick to C, but there really are things in C++ that are worth using, even if you mostly use C. C++'s automatic memory management facilities (not just string, but also auto_ptr/unique_ptr and more) fall into this category.
Plus, C++ strings operate more like Tcl strings, so you'll probably be more comfortable with them.
Factual assertions in comments must always be true, or they are likely mislead you later, potentially hazardously so. Your particular USB to serial adapter may use /dev/ttyACMx, but not all do. There's another common USB device class used by some serial-to-USB adapters that causes them to show up under Linux as ttyUSBx. More generally, a future change may change the device name in some other way; you might port to BSD, for example, and now your USB to serial device is called /dev/cu.usbserial, blowing your 15-byte port buffer. Don't assume.
Even with the BSD case aside, your port buffer should not be smaller than your line buffer, since you are concatenating the latter onto the former. At minimum, sizeof(port) should be sizeof(line) + strlen("/dev/"), just in case. If that seems excessive, it is only because 128 bytes for the line buffer is unnecessarily large. (Not that I'm trying to twist your arm to change it. RAM is cheap; programmer debugging time is expensive.)
Next:
fcntl(cfd, F_SETFL, 0); // blocking mode
File handles are blocking by default in Unix. You have to ask for a nonblocking file handle. Anyway, blasting all the flags is bad style; you don't know what other flags you're changing here. Proper style is to get, modify, then set, much like the way you're doing with tcsetattr():
int flags;
fcntl(cfd, F_GETFL, &flags);
flags &= ~O_NONBLOCK;
fcntl(cfd, F_SETFL, flags);
Well, you're kind of using tcsetattr() correctly:
tcsetattr(cfd, TCSANOW, &options);
...followed by further modifications to options without a second call to tcsetattr(). Oops!
You weren't under the impression that modifications to the options structure affect the serial port immediately, were you?
if (write(cfd, msgOut, 3) < 3) {
logIt(fprintf(lfd, "Sending of output message failed\n"));
close(cfd);
continue;
}
Piles of wrong here:
You're collapsing the short-write and error cases. Handle them separately:
int bytes = write(cfd, msgOut, 3);
if (bytes == 0) {
// can't happen with USB, but you may later change to a
// serial-to-Ethernet bridge (e.g. Digi One SP), and then
// it *can* happen under TCP.
//
// complain, close, etc.
}
else if (bytes < 0) {
// plain failure case; could collapse this with the == 0 case
// close, etc
}
else if (bytes < 3) {
// short write case
}
else {
// success case
}
You aren't logging errno or its string equivalent, so when (!) you get an error, you won't know which error:
logIt(fprintf(lfd, "Sending of output message failed: %s (code %d)\n",
strerror(errno), errno));
Modify to taste. Just realize that write(2), like most other Unix system calls, has a whole bunch of possible error codes. You probably don't want to handle all of them the same way. (e.g. EINTR)
After closing the FD, you're leaving it set to a valid FD value, so that on EOF after reading one line, you leave the function with a valid but closed FD value! (This is the problem with break above: it can implicitly return a closed FD to its caller.) Say cfd = -1 after every close(cfd) call.
Everything written above about write() also applies to the following read() call, but also:
if (read(cfd, msgIn, 4) != 4) {
There's nothing in POSIX that tells you that if the serial device sends 4 bytes that you will get all 4 bytes in a single read(), even with a blocking FD. You are especially unlikely to get more than one byte per read() with slow serial ports, simply because your program is lightning fast compared to the serial port. You need to call read() in a loop here, exiting only on error or completion.
And just in case it isn't obvious:
remove("usbSerial");
You don't need that if you switch to popen() above. Don't scatter temporary working files around the file system where a pipe will do.

How can I set the BLE connection timeout of gatttool on Raspberry Pi?

I connect to a bluetooth le peripheral with the following command:
gatttool -t random -b xx:xx:xx:xx:xx:xx -I
and connect
If the given MAC-address exists, I have no problem.
If the given MAC-Address does not exist, the gatttool trys to connect about 40 seconds, till the gatttool response is "Error: connect error: Connection refused (111)".
My question is, how and where can i change the 40 seconds connection timeout of gatttool?
The connection timeout is defined in the bluetooth module of the Linux kernel (L2CAP_CONN_TIMEOUT) and there is no way to change it in userspace. (There’s another constant, HCI_LE_CONN_TIMEOUT, but I don’t think that’s used for this purpose.) However, I believe that if you close the connection or kill the process, the kernel should send the proper LE Create Connection Cancel command so that you can connect to someone else shortly thereafter.
Unfortunately I don't think there is anyway to do this unless you want to change the gatttool code. I had a look previously and can see in the code that gatttool does a blocking socket "connect" call.
If you are ready to change the gatttool code then you will need to add a timeout on the connection socket in Bluez.
I had to do the same workaround when I wrote GattLib to avoid to block the retry.
You can see my change in this commit: https://github.com/labapart/gattlib/commit/ee58e4cb64af6c698dea1fabb5b6d5e0fc174883
But the main changes are these lines:
if (setsockopt (sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0) {
fprintf(stderr, "l2cap_connect: Failed to setsockopt for receive timeout.\n");
return -1;
}
if (setsockopt (sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout)) < 0) {
fprintf(stderr, "l2cap_connect: Failed to setsockopt for sending timeout.\n");
return -1;
}
You might be interested by the GattLib example ble_scan if you want to write your own code.

Dial -Out with Asterisk Sip - circuit is busy error

Okey İ handled my problem,
Problem is provider. it is rejected my request! All problem provider that means trunk!
I have a asterisk server 1.6 and a trunk. i tried to call my cell phone on trunk(provider)
when i call my cell phone it gives me :
-- Executing [0506610XXXX#phone:1] NoOp("SIP/1001-0000009b", "") in new stack
-- Executing [0506610XXXX#phone:2] Dial("SIP/1001-0000009b", "SIP/312XXXXXXX
/0506610XXXX") in new stack
== Using SIP RTP CoS mark 5
-- Called 312XXXXXXX/0506610XXXX
-- SIP/3XXXXXXXX-0000009c is circuit-busy
== Everyone is busy/congested at this time (1:0/1/0)
-- Executing [0506610XXXX#phone:3] Hangup("SIP/1001-0000009b", "") in new stack
== Spawn extension (phone, 0506610XXXX, 3) exited non-zero on 'SIP/1001-0000009b'
i tried varios things;
#sip show peers- all ok all registered
#sip show registry - my trunk is ok registered
my sip.conf
[general]
register=>XXXXXX:XXXXXX#ipaddress/312911
[312911]
type=friend
secret=XXXXX
username=312911
host=ipaddress
insecure=invite ,port
context=aaa
[1001]
type=friend
dtmfmode=rfc2833
context=phone
host=dynamic
secret=XX
callerID="1001"<1001>
nat=yes
my extension.conf
[myphones]
exten=> _XXX.,1,NoOp()
exten=> _XXX.,n,Dial(SIP/312911/${EXTEN})
exten=> _XXX.,n,Hangup()
[incoming]
exten=>_X.,1,NoOp()
exten=>_X.,n,Dial(SIP/1001)
exten=> _X.,n,Hangup()
[internal]
exten=>_1XXX,1,Dial(SIP/${EXTEN})
exten=>_1XXX,n,Hangup()
[phone]
include=>internal
include=>myphones
[aaa]
include=>incoming
include=>myphones
Some common causes which will generate this kind of error:
1) Provider needs registration where you are not giving register and only created peer.
2) The format is wrong. Some provider needs 00 as ISD, some do not. So check that you are using the correct number format.
3) The outbound circuit is full. It happens where there is no channel left from the provider side or you are not allowed to create more channels.
4) Some providers don't support multiple registry.
Fore more details you need to enable "sip set debug ip < provider ip address> and then make the call and check each packet.
on asterisk console:
set verbose 0 // optional
set debug 0 // optional
set sip debug
it seems that your trunk is not working(wrong number format, invalid login/pass,...)
in sip messages U'll see real error

Resources