Correct use of le_set_scan_response_data_cp / hci_send_req ?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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;
}

[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux