Hello, I try to create a btle server which does advertise itsself with the name "HEY". Attached is a demo program. Compile with: g++ -o leserv leserv.cpp -lbluetooth then start the program as root. And on another host start: hcitool lescan The current version prints "HEY" but I think the API is wrong here. Every other version which can be found on the internet uses the // does not work //hci_le_set_scan_response_data(hciSocket,(uint8_t*)msg,strlen(msg),0); implementation, and this one does not work. What would be a correct example for this task? regards, Martin
/* Compile with: g++ -o leserv leserv.cpp -lbluetooth */ #include <errno.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <sys/ioctl.h> #include <sys/prctl.h> #include <unistd.h> #include <bluetooth/bluetooth.h> #include <bluetooth/hci.h> #include <bluetooth/hci_lib.h> int lastSignal = 0; static void signalHandler(int signal) { lastSignal = signal; } int hci_le_set_advertising_data(int dd, uint8_t* data, uint8_t length, int to) { struct hci_request rq; le_set_advertising_data_cp data_cp; uint8_t status; memset(&data_cp, 0, sizeof(data_cp)); data_cp.length = length; memcpy(&data_cp.data, data, sizeof(data_cp.data)); memset(&rq, 0, sizeof(rq)); rq.ogf = OGF_LE_CTL; rq.ocf = OCF_LE_SET_ADVERTISING_DATA; rq.cparam = &data_cp; rq.clen = LE_SET_ADVERTISING_DATA_CP_SIZE; rq.rparam = &status; rq.rlen = 1; if (hci_send_req(dd, &rq, to) < 0) return -1; if (status) { errno = EIO; return -1; } return 0; } int hci_le_set_scan_response_data(int dd, uint8_t* data, uint8_t length, int to) { struct hci_request rq; le_set_scan_response_data_cp data_cp; uint8_t status; memset(&data_cp, 0, sizeof(data_cp)); data_cp.length = length; memcpy(&data_cp.data, data, sizeof(data_cp.data)); memset(&rq, 0, sizeof(rq)); rq.ogf = OGF_LE_CTL; rq.ocf = OCF_LE_SET_SCAN_RESPONSE_DATA; rq.cparam = &data_cp; rq.clen = LE_SET_SCAN_RESPONSE_DATA_CP_SIZE; rq.rparam = &status; rq.rlen = 1; if (hci_send_req(dd, &rq, to) < 0) return -1; if (status) { errno = EIO; return -1; } return 0; } int le_advertise_enable(int hciSocket, int hciDeviceId, int previousAdapterState) { struct hci_dev_info hciDevInfo; int currentAdapterState; const char* adapterState = NULL; memset(&hciDevInfo, 0x00, sizeof(hciDevInfo)); hciDevInfo.dev_id = hciDeviceId; // get HCI dev info for adapter state ioctl(hciSocket, HCIGETDEVINFO, (void *)&hciDevInfo); currentAdapterState = hci_test_bit(HCI_UP, &hciDevInfo.flags); if (previousAdapterState != currentAdapterState) { previousAdapterState = currentAdapterState; if (!currentAdapterState) { adapterState = "poweredOff"; } else { hci_le_set_advertise_enable(hciSocket, 0, 1000); hci_le_set_advertise_enable(hciSocket, 1, 1000); if (hci_le_set_advertise_enable(hciSocket, 0, 1000) == -1) { switch (errno) { case EPERM: adapterState = "unauthorized"; break; case EIO: adapterState = "unsupported"; break; case ETIMEDOUT: adapterState = "timedout"; break; default: printf("advertiseErrno %d\n", errno); adapterState = "unknown"; break; } } else { adapterState = "poweredOn"; } } printf("adapterState %s\n", adapterState); } return currentAdapterState; } void setScanResponseData(int socket,uint8_t* data, uint8_t length) { printf("Scan response data: len:%d\n",length); for (uint8_t i = 0; i < length; ++i) { printf("%02x ", data[i]); } printf("\n"); int timeout = 0; // infinite le_set_scan_response_data_cp cp; memset(&cp, 0, sizeof(cp)); cp.length = length+2; cp.data[0]=length+2; cp.data[1]=0x8; memcpy(&cp.data[2], data, length); struct hci_request rq; uint8_t status; memset(&rq, 0, sizeof(rq)); rq.ogf = OGF_LE_CTL; rq.ocf = OCF_LE_SET_SCAN_RESPONSE_DATA; rq.cparam = &cp; rq.clen = LE_SET_SCAN_RESPONSE_DATA_CP_SIZE; rq.rparam = &status; rq.rlen = 1; if (hci_send_req(socket, &rq, timeout) < 0) { perror("hci_send_req\n"); printf("1-Error setting advertising data\n"); } if (status) { printf("2-Error setting advertising data"); } } int main(int argc, const char* argv[]) { const char *hciDeviceIdOverride = NULL; int hciDeviceId = 0; int hciSocket; //struct hci_dev_info hciDevInfo; //int previousAdapterState = -1; int currentAdapterState=-1; const char* adapterState = NULL; fd_set rfds; struct timeval tv; int selectRetval; char stdinBuf[256 * 2 + 1]; char advertisementDataBuf[256]; int advertisementDataLen = 0; char scanDataBuf[256]; int scanDataLen = 0; int len; int i; // memset(&hciDevInfo, 0x00, sizeof(hciDevInfo)); // remove buffering setbuf(stdin, NULL); setbuf(stdout, NULL); setbuf(stderr, NULL); // setup signal handlers signal(SIGINT, signalHandler); signal(SIGKILL, signalHandler); signal(SIGHUP, signalHandler); signal(SIGUSR1, signalHandler); prctl(PR_SET_PDEATHSIG, SIGINT); if (argc > 1 && strlen(argv[1]) > 0) { hciDeviceIdOverride = argv[1]; } if (hciDeviceIdOverride != NULL) { hciDeviceId = atoi(hciDeviceIdOverride); } else { // if no env variable given, use the first available device hciDeviceId = hci_get_route(NULL); } if (hciDeviceId < 0) { hciDeviceId = 0; // use device 0, if device id is invalid } printf("hciDeviceId %d\n", hciDeviceId); // setup HCI socket hciSocket = hci_open_dev(hciDeviceId); //hciDevInfo.dev_id = hciDeviceId; if (hciSocket == -1) { printf("adapterState unsupported\n"); return -1; } const char* msg="HEY"; while(1) { FD_ZERO(&rfds); FD_SET(0, &rfds); FD_SET(hciSocket, &rfds); tv.tv_sec = 1; tv.tv_usec = 0; currentAdapterState=le_advertise_enable(hciSocket,hciDeviceId, currentAdapterState); // stop advertising hci_le_set_advertise_enable(hciSocket, 0, 1000); // works setScanResponseData(hciSocket,(uint8_t*)msg,strlen(msg)); // does not work //hci_le_set_scan_response_data(hciSocket,(uint8_t*)msg,strlen(msg),0); // start advertising hci_le_set_advertise_enable(hciSocket, 1, 1000); selectRetval = select(hciSocket + 1, &rfds, NULL, NULL, &tv); printf("selectRetval:%d\n",selectRetval); if (-1 == selectRetval) { if (SIGINT == lastSignal || SIGKILL == lastSignal) { // done break; } else if (SIGHUP == lastSignal) { // stop advertising hci_le_set_advertise_enable(hciSocket, 0, 1000); } else if (SIGUSR1 == lastSignal) { printf("SIGUSR1\n"); } } else if (selectRetval) { if (FD_ISSET(0, &rfds)) { len = read(0, stdinBuf, sizeof(stdinBuf)); printf("len:%d\n",len); if (len <= 0) { break; } i = 0; advertisementDataLen = 0; while(i < len && stdinBuf[i] != ' ') { unsigned int data = 0; int token=sscanf(&stdinBuf[i], "%02x", &data); advertisementDataBuf[advertisementDataLen] = data; printf("databuf[%d]=%x (token:%d)\n",advertisementDataLen,data,token); advertisementDataLen++; i += 2; } i++; scanDataLen = 0; while(i < len && stdinBuf[i] != '\n') { unsigned int data = 0; sscanf(&stdinBuf[i], "%02x", &data); scanDataBuf[scanDataLen] = data; printf("scanbuf[%d]=%x\n",scanDataLen,data); scanDataLen++; i += 2; } const char* mesg="Martin"; // stop advertising hci_le_set_advertise_enable(hciSocket, 0, 1000); // set scan data hci_le_set_scan_response_data(hciSocket, (uint8_t*)&scanDataBuf, scanDataLen, 1000); // set advertisement data hci_le_set_advertising_data(hciSocket, (uint8_t*)&advertisementDataBuf, advertisementDataLen, 1000); // start advertising hci_le_set_advertise_enable(hciSocket, 1, 1000); // set scan data hci_le_set_scan_response_data(hciSocket, (uint8_t*)&scanDataBuf, scanDataLen, 1000); // set advertisement data hci_le_set_advertising_data(hciSocket, (uint8_t*)&advertisementDataBuf, advertisementDataLen, 1000); } } } // stop advertising hci_le_set_advertise_enable(hciSocket, 0, 1000); close(hciSocket); return 0; }