//
//  bt_main.c
//
//  Created by hark on 2014/06/13.
//  Copyright (c) 2014 hark. All rights reserved.
//
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>

#include "bt_const.h"
#include "bt_extern.h"
#include "bt_printf.h"
#include "bt_hsp.h"
#include "bt_hfp.h"
#include "bt_sco.h"
#include "bt_main.h"

static int set_class()
{
  
  const unsigned int cls = 0x280404;
  const int timeout = 1000;
  int id;
  int fh;
  bdaddr_t btaddr;
  char pszaddr[18];
  
  // get the device ID
  // passing in NULL instead of a bdaddr_t will
  // give the ID of the first bluetooth device
  if ((id = hci_get_route(NULL)) < 0)
    return -1;
  
  // convert the device ID into a 6 byte bluetooth address
  if (hci_devba(id, &btaddr) < 0)
    return -1;
  
  // convert the address into a zero terminated string
  if (ba2str(&btaddr, pszaddr) < 0)
    return -1;
  
  // open a file handle to the HCI
  if ((fh = hci_open_dev(id)) < 0)
    return -1;
  
  // set the class
  if (hci_write_class_of_dev(fh, cls, timeout) != 0)
    {
      perror("hci_write_class ");
      hci_close_dev(fh);
      return -1;
    }
  
  // close the file handle
  hci_close_dev(fh);
  
  debug_printf("set device %s to class: 0x%06x\n", pszaddr, cls);
  
  return 0;
}


static void *recv_loop(void *param)
{
  
  int sock = (long int)param;
  
  struct sco_options so;
  int so_size = sizeof(so);
  getsockopt(sock, SOL_SCO, SCO_OPTIONS, &so, &so_size);
  const uint16_t max_packet_size = so.mtu;
  
  fd_set rfds;
  
  char *buf = (char *)malloc(max_packet_size);
  
  size_t readsize;
  
  FD_ZERO(&rfds);
  FD_SET(sock, &rfds);
  
  while (select(sock + 1, &rfds, NULL, NULL, NULL) > 0) {
    
    readsize = recv(sock, buf, sizeof(buf), 0);
    
    FD_ZERO(&rfds);
    FD_SET(sock, &rfds);
    
  }
  
  free(buf);
  
  debug_printf("exit sco recv loop\n");
  
  return(NULL);
}




static int make_rfcomm( const char * const dest,
			const uint8_t channel)
{
  int sock = 0;
  int status = 0;
  
  struct sockaddr_rc addr = {
    .rc_family = AF_BLUETOOTH,
    .rc_bdaddr = 0,
    .rc_channel = channel,
  };
  
  // alloc a socket
  sock = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
  if (sock < 0) {
    perror("alloc a rfcomm socket");
    return(-1);
  }
  str2ba(dest, &addr.rc_bdaddr);
  
  // connect to server
  status = connect(sock, (struct sockaddr *)&addr, sizeof(addr));	
  if (status < 0) {
    perror("connect to server");
    close(sock);
    return(-1);
  }
  
  return(0);
}

static int check_vs(void)
{
  
  int adapter_id = 0;
  int sock = 0;
  adapter_id = hci_get_route(NULL);
  if (adapter_id < 0) {
    perror("adapter_id");
    return(-1);
  }
  sock = hci_open_dev(adapter_id);
  if (sock < 0) {
    perror("open socket");
    return(-1);
  }
  
  {
    uint16_t vs = 0;
    int ret = 0;
    ret = hci_read_voice_setting(sock, &vs, 1000);
    if (ret < 0) {
      perror("voice setting");
      close(sock);
      return(-1);
    }
    debug_printf("vs = 0x%02x\n", (int)vs);
#if 1
    ret = hci_write_voice_setting(sock, vs, 1000);
    if (ret < 0) {
      perror("voice setting");
      close(sock);
      return(-1);
    }
#endif
    
  }
  
  //close(sock);
  
  return(0);
}



int bt_init()
{

#if 0
  if (set_class() != 0) {
    return(-1);
  }
#endif
  
  if (register_sdp_hsp(hsp_channel) != 0) {
    return(-1);
  }
  
  if (register_sdp_hfp(hfp_channel) != 0) {
    return(-1);
  }

  if (init_rfcomm() != 0) {
    return(-1);
  }
  
  if (make_rfcomm_server(hsp_channel) != 0) {
    return(-1);
  }
  
  if (make_rfcomm_server(hfp_channel) != 0) {
    return(-1);
  }
  
  if (init_sco() != 0) {
    return(-1);
  }

  if (make_sco_server() != 0) {
    return(-1);
  }
  
  return(0);
  
}
