Files
BPI-CM9-Linux/aml-comp/vendor/amlogic/bluez/tools/btgatt-server.c
T
2026-08-24 10:03:24 +08:00

1070 lines
25 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2014 Google Inc.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <ctype.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <time.h>
#include <stdlib.h>
#include <getopt.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "lib/bluetooth.h"
#include "lib/hci.h"
#include "lib/hci_lib.h"
#include "lib/l2cap.h"
#include "lib/uuid.h"
#include "monitor/bt.h"
#include "src/shared/mainloop.h"
#include "src/shared/util.h"
#include "src/shared/att.h"
#include "src/shared/hci.h"
#include "src/shared/queue.h"
#include "src/shared/timeout.h"
#include "src/shared/gatt-db.h"
#include "src/shared/gatt-server.h"
#define UUID_GAP 0x1800
#define UUID_GATT 0x1801
#ifdef DUEROS
#define UUID_DEVICE_INFO 0x1111
#define UUID_USER_CHAR 0x2222
#else
#define UUID_DEVICE_INFO 0x180A
#define UUID_USER_CHAR 0x9999
#endif
static struct hci_dev_info hdi;
static int ctl;
static pthread_t thread_id;
static int wifi_configured = 0;
static struct server *server;
#define ATT_CID 4
#define PRLOG(...) \
do { \
printf("BLUEZ-GATT: "__VA_ARGS__); \
} while (0)
#define COLOR_OFF "\x1B[0m"
#define COLOR_RED "\x1B[0;91m"
#define COLOR_GREEN "\x1B[0;92m"
#define COLOR_YELLOW "\x1B[0;93m"
#define COLOR_BLUE "\x1B[0;94m"
#define COLOR_MAGENTA "\x1B[0;95m"
#define COLOR_BOLDGRAY "\x1B[1;30m"
#define COLOR_BOLDWHITE "\x1B[1;37m"
static bool verbose = false;
struct server {
int fd;
struct bt_att *att;
struct gatt_db *db;
struct bt_gatt_server *gatt;
uint8_t *device_name;
size_t name_len;
uint16_t gatt_svc_chngd_handle;
bool svc_chngd_enabled;
struct gatt_db_attribute *chara_att;
uint16_t chara_handle;
};
typedef struct {
int server_sockfd;
int client_sockfd[10];
int client_num;
int server_len;
int client_len;
struct sockaddr_un server_address;
struct sockaddr_un client_address;
char sock_path[64];
} tAPP_SOCKET;
tAPP_SOCKET sk_handle;
char socket_path[] = "/data/etc/rtk/config/aml_rtkble_socket";
int rtk_ble_sk = 0;
char socket_rev[256] = {0};
int rtk_socket_rev_len = 1;
/*******************config wifi zone************************************************/
char start[1] = {0x01};
char magic[10] = "amlogicble";
char cmd[9] = "wifisetup";
char ssid[33] = {0};
char psk[64] = {0};
char end[1] = {0x04};
#define FRAME_BUF_MAX (1+10+9+32+63+1)
char version[8] = "20171211";
char frame_buf[FRAME_BUF_MAX] = {0};
char ssid_psk_file[] = "/var/www/cgi-bin/wifi/select.txt";
/*0: wifi set success, 1: wifi set fail*/
char wifi_status_file[] = "/etc/bluetooth/wifi_status";
char wifi_status = 0;
char wifi_success = '1';
void ble_init(void);
int config_wifi(const uint8_t *arg, int len)
{
int ret = 0;
int check_0 = 0;
FILE *fd;
if (len > 0) {
memset(frame_buf, 0, FRAME_BUF_MAX);
memcpy(frame_buf, arg, len);
PRLOG("frame_buf:%s, len:%d, FRAME_BUF_MAX:%d\n", frame_buf, len, FRAME_BUF_MAX);
check_0 = 0;
if (len > FRAME_BUF_MAX) {
PRLOG("len too long, max buf length exceeded!!!\n");
return -1;
}
if ((frame_buf[0] == 0x01)
&& (frame_buf[len - 1] == 0X04)) {
PRLOG("frame start and end is right\n");
if (!strncmp(magic, frame_buf + 1, 10)) {
PRLOG("magic : %s\n", magic);
PRLOG("version : %s\n", version);
check_0 = 1;
} else {
PRLOG("magic of frame error!!!\n");
memset(frame_buf, 0, FRAME_BUF_MAX);
check_0 = 0;
}
} else {
PRLOG("start or end of frame error!!!\n");
memset(frame_buf, 0, FRAME_BUF_MAX);
check_0 = 0;
}
if (check_0 == 1) {
if (!strncmp("wifisetup", frame_buf + 11, 9)) {
strncpy(ssid, frame_buf + 20, 32);
strncpy(psk, frame_buf + 52, 63);
PRLOG("WiFi setup,ssid:%s,psk:%s frame_buf:%s\n", ssid, psk,frame_buf);
system("rm -rf /var/www/cgi-bin/wifi/select.txt");
system("touch /var/www/cgi-bin/wifi/select.txt");
system("chmod 644 /var/www/cgi-bin/wifi/select.txt");
fd = fopen(ssid_psk_file, "wb");
if (!fd) {
PRLOG("open ssid_psk_file file failed\n");
return -1;
}
ret = fwrite(ssid, 1, strlen(ssid), fd);
if (ret != strlen(ssid)) {
PRLOG("write wifi ssid error\n");
}
ret = fwrite("\n", 1, 1, fd);
if (ret != 1) {
PRLOG("write enter and feedline error\n");
}
ret = fwrite(psk, 1, strlen(psk), fd);
if (ret != strlen(psk)) {
PRLOG("write wifi password error\n");
}
fflush(fd);
check_0 = 0;
memset(frame_buf, 0, FRAME_BUF_MAX);
fclose(fd);
wifi_configured = 1;
}
}
}
return 0;
}
/*******************config wifi zone end*********************************************/
/*********************************socket ***************************************************/
int setup_socket_server(tAPP_SOCKET *app_socket)
{
unlink (app_socket->sock_path);
if ((app_socket->server_sockfd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) {
PRLOG("fail to create socket\n");
perror("socket");
return -1;
}
app_socket->server_address.sun_family = AF_UNIX;
strcpy (app_socket->server_address.sun_path, app_socket->sock_path);
memset(app_socket->client_sockfd, 0, sizeof(app_socket->client_sockfd));
app_socket->client_num = 0;
app_socket->server_len = sizeof (app_socket->server_address);
app_socket->client_len = sizeof (app_socket->client_address);
if ((bind (app_socket->server_sockfd, (struct sockaddr *)&app_socket->server_address, app_socket->server_len)) < 0) {
perror("bind");
return -1;
}
if (listen (app_socket->server_sockfd, 10) < 0) {
perror("listen");
return -1;
}
PRLOG ("Socket is ready for client connect...\n");
return 0;
}
int accpet_client(tAPP_SOCKET *app_socket)
{
int sk = 0;
sk = accept (app_socket->server_sockfd, (struct sockaddr *)&app_socket->server_address, (socklen_t *)&app_socket->client_len);
if (sk == -1) {
perror ("accept");
return -1;
}
app_socket->client_sockfd[app_socket->client_num] = sk;
app_socket->client_num++;
return sk;
}
/*********************************end socket **********************************************/
static struct bt_hci *hci_dev;
static void print_prompt(void)
{
PRLOG(COLOR_BLUE "[GATT server]" COLOR_OFF "# ");
fflush(stdout);
}
static void att_disconnect_cb(int err, void *user_data)
{
PRLOG("Device disconnected: %s\n", strerror(err));
mainloop_quit();
}
static void att_debug_cb(const char *str, void *user_data)
{
const char *prefix = user_data;
PRLOG(COLOR_BOLDGRAY "%s" COLOR_BOLDWHITE "%s\n" COLOR_OFF, prefix,
str);
}
static void gatt_debug_cb(const char *str, void *user_data)
{
const char *prefix = user_data;
PRLOG(COLOR_GREEN "%s%s\n" COLOR_OFF, prefix, str);
}
static void gap_device_name_read_cb(struct gatt_db_attribute *attrib,
unsigned int id, uint16_t offset,
uint8_t opcode, struct bt_att *att,
void *user_data)
{
struct server *server = user_data;
uint8_t error = 0;
size_t len = 0;
const uint8_t *value = NULL;
PRLOG("GAP Device Name Read called\n");
len = server->name_len;
if (offset > len) {
error = BT_ATT_ERROR_INVALID_OFFSET;
goto done;
}
len -= offset;
value = len ? &server->device_name[offset] : NULL;
done:
gatt_db_attribute_read_result(attrib, id, error, value, len);
}
static void gap_device_name_write_cb(struct gatt_db_attribute *attrib,
unsigned int id, uint16_t offset,
const uint8_t *value, size_t len,
uint8_t opcode, struct bt_att *att,
void *user_data)
{
struct server *server = user_data;
uint8_t error = 0;
PRLOG("GAP Device Name Write called\n");
/* If the value is being completely truncated, clean up and return */
if (!(offset + len)) {
free(server->device_name);
server->device_name = NULL;
server->name_len = 0;
goto done;
}
/* Implement this as a variable length attribute value. */
if (offset > server->name_len) {
error = BT_ATT_ERROR_INVALID_OFFSET;
goto done;
}
if (offset + len != server->name_len) {
uint8_t *name;
name = realloc(server->device_name, offset + len);
if (!name) {
error = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
goto done;
}
server->device_name = name;
server->name_len = offset + len;
}
if (value)
memcpy(server->device_name + offset, value, len);
done:
gatt_db_attribute_write_result(attrib, id, error);
}
static void gap_device_name_ext_prop_read_cb(struct gatt_db_attribute *attrib,
unsigned int id, uint16_t offset,
uint8_t opcode, struct bt_att *att,
void *user_data)
{
uint8_t value[2];
PRLOG("Device Name Extended Properties Read called\n");
value[0] = BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE;
value[1] = 0;
gatt_db_attribute_read_result(attrib, id, 0, value, sizeof(value));
}
static void gatt_service_changed_cb(struct gatt_db_attribute *attrib,
unsigned int id, uint16_t offset,
uint8_t opcode, struct bt_att *att,
void *user_data)
{
PRLOG("Service Changed Read called\n");
gatt_db_attribute_read_result(attrib, id, 0, NULL, 0);
}
static void gatt_svc_chngd_ccc_read_cb(struct gatt_db_attribute *attrib,
unsigned int id, uint16_t offset,
uint8_t opcode, struct bt_att *att,
void *user_data)
{
struct server *server = user_data;
uint8_t value[2];
PRLOG("Service Changed CCC Read called\n");
value[0] = server->svc_chngd_enabled ? 0x02 : 0x00;
value[1] = 0x00;
gatt_db_attribute_read_result(attrib, id, 0, value, sizeof(value));
}
static void gatt_svc_chngd_ccc_write_cb(struct gatt_db_attribute *attrib,
unsigned int id, uint16_t offset,
const uint8_t *value, size_t len,
uint8_t opcode, struct bt_att *att,
void *user_data)
{
struct server *server = user_data;
uint8_t ecode = 0;
PRLOG("Service Changed CCC Write called\n");
if (!value || len != 2) {
ecode = BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN;
goto done;
}
if (offset) {
ecode = BT_ATT_ERROR_INVALID_OFFSET;
goto done;
}
if (value[0] == 0x00)
server->svc_chngd_enabled = false;
else if (value[0] == 0x02)
server->svc_chngd_enabled = true;
else
ecode = 0x80;
PRLOG("Service Changed Enabled: %s\n",
server->svc_chngd_enabled ? "true" : "false");
done:
gatt_db_attribute_write_result(attrib, id, ecode);
}
static void user_service_read_cb(struct gatt_db_attribute *attrib,
unsigned int id, uint16_t offset,
uint8_t opcode, struct bt_att *att,
void *user_data)
{
// PRLOG("user_service_read_cb\n");
gatt_db_attribute_read_result(attrib, id, 0, &wifi_status, 1);
}
static void user_service_write_cb(struct gatt_db_attribute *attrib,
unsigned int id, uint16_t offset,
const uint8_t *value, size_t len,
uint8_t opcode, struct bt_att *att,
void *user_data)
{
int i;
struct server *server = (struct server *)user_data;
PRLOG("%s enter, data len =%d\n", __func__, len);
#ifdef DUEROS
//Ble socket send
PRLOG ("msg to duerOS: %s\t length: %d\n", value, len);
send(rtk_ble_sk, value, len, 0);
#else
config_wifi(value, len);
#endif
gatt_db_attribute_write_result(attrib, id, 0);
}
static void confirm_write(struct gatt_db_attribute *attr, int err,
void *user_data)
{
if (!err)
return;
fprintf(stderr, "Error caching attribute %p - err: %d\n", attr, err);
exit(1);
}
static void user_service_descrip_read_cb(struct gatt_db_attribute *attrib,
unsigned int id, uint16_t offset,
uint8_t opcode, struct bt_att *att,
void *user_data)
{
uint8_t value[2];
value[0] = 0x01;
value[1] = 0x00;
gatt_db_attribute_read_result(attrib, id, 0, value, 2);
}
static void user_service_descrip_write_cb(struct gatt_db_attribute *attrib,
unsigned int id, uint16_t offset,
const uint8_t *value, size_t len,
uint8_t opcode, struct bt_att *att,
void *user_data)
{
int i;
PRLOG("%s enter, data =%s\t len =%d\n", __func__, value, len);
for (i = 0; i < len; i++)
PRLOG ("Write 0x2902 : %d\t%x\n", value[i], value[i]);
gatt_db_attribute_write_result(attrib, id, 0);
}
static void populate_gap_service(struct server *server)
{
bt_uuid_t uuid;
struct gatt_db_attribute *service, *tmp;
uint16_t appearance;
/* Add the GAP service */
bt_uuid16_create(&uuid, UUID_GAP);
service = gatt_db_add_service(server->db, &uuid, true, 6);
/*
* Device Name characteristic. Make the value dynamically read and
* written via callbacks.
*/
bt_uuid16_create(&uuid, GATT_CHARAC_DEVICE_NAME);
gatt_db_service_add_characteristic(service, &uuid,
BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
BT_GATT_CHRC_PROP_READ |
BT_GATT_CHRC_PROP_EXT_PROP,
gap_device_name_read_cb,
gap_device_name_write_cb,
server);
bt_uuid16_create(&uuid, GATT_CHARAC_EXT_PROPER_UUID);
gatt_db_service_add_descriptor(service, &uuid, BT_ATT_PERM_READ,
gap_device_name_ext_prop_read_cb,
NULL, server);
/*
* Appearance characteristic. Reads and writes should obtain the value
* from the database.
*/
bt_uuid16_create(&uuid, GATT_CHARAC_APPEARANCE);
tmp = gatt_db_service_add_characteristic(service, &uuid,
BT_ATT_PERM_READ,
BT_GATT_CHRC_PROP_READ,
NULL, NULL, server);
/*
* Write the appearance value to the database, since we're not using a
* callback.
*/
put_le16(128, &appearance);
gatt_db_attribute_write(tmp, 0, (void *) &appearance,
sizeof(appearance),
BT_ATT_OP_WRITE_REQ,
NULL, confirm_write,
NULL);
gatt_db_service_set_active(service, true);
}
static void populate_gatt_service(struct server *server)
{
bt_uuid_t uuid;
struct gatt_db_attribute *service, *svc_chngd;
/* Add the GATT service */
bt_uuid16_create(&uuid, UUID_GATT);
service = gatt_db_add_service(server->db, &uuid, true, 4);
bt_uuid16_create(&uuid, GATT_CHARAC_SERVICE_CHANGED);
svc_chngd = gatt_db_service_add_characteristic(service, &uuid,
BT_ATT_PERM_READ,
BT_GATT_CHRC_PROP_READ | BT_GATT_CHRC_PROP_INDICATE,
gatt_service_changed_cb,
NULL, server);
server->gatt_svc_chngd_handle = gatt_db_attribute_get_handle(svc_chngd);
bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
gatt_db_service_add_descriptor(service, &uuid,
BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
gatt_svc_chngd_ccc_read_cb,
gatt_svc_chngd_ccc_write_cb, server);
gatt_db_service_set_active(service, true);
}
static void populate_user_service(struct server *server)
{
bt_uuid_t uuid;
struct gatt_db_attribute *service, *characteristic;
bt_uuid16_create(&uuid, UUID_DEVICE_INFO);
service = gatt_db_add_service(server->db, &uuid, true, 8);
bt_uuid16_create(&uuid, UUID_USER_CHAR);
server->chara_att = gatt_db_service_add_characteristic(service, &uuid,
BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
BT_GATT_CHRC_PROP_NOTIFY | BT_GATT_CHRC_PROP_WRITE | BT_GATT_CHRC_PROP_INDICATE | BT_GATT_CHRC_PROP_READ,
user_service_read_cb,
user_service_write_cb,
server);
server->chara_handle = gatt_db_attribute_get_handle(server->chara_att);
bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
gatt_db_service_add_descriptor(service, &uuid,
BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
user_service_descrip_read_cb,
user_service_descrip_write_cb,
server);
gatt_db_service_set_active(service, true);
}
static struct server *server_create(int fd)
{
struct server *server;
server = new0(struct server, 1);
if (!server) {
fprintf(stderr, "Failed to allocate memory for server\n");
return NULL;
}
server->att = bt_att_new(fd, false);
if (!server->att) {
fprintf(stderr, "Failed to initialze ATT transport layer\n");
goto fail;
}
if (!bt_att_set_close_on_unref(server->att, true)) {
fprintf(stderr, "Failed to set up ATT transport layer\n");
goto fail;
}
if (!bt_att_register_disconnect(server->att, att_disconnect_cb, NULL,
NULL)) {
fprintf(stderr, "Failed to set ATT disconnect handler\n");
goto fail;
}
server->fd = fd;
server->db = gatt_db_new();
if (!server->db) {
fprintf(stderr, "Failed to create GATT database\n");
goto fail;
}
server->gatt = bt_gatt_server_new(server->db, server->att, 0);
if (!server->gatt) {
fprintf(stderr, "Failed to create GATT server\n");
goto fail;
}
if (verbose) {
bt_att_set_debug(server->att, att_debug_cb, "att: ", NULL);
bt_gatt_server_set_debug(server->gatt, gatt_debug_cb,
"server: ", NULL);
}
/* Random seed for generating fake Heart Rate measurements */
srand(time(NULL));
/* bt_gatt_server already holds a reference */
populate_gap_service(server);
populate_gatt_service(server);
populate_user_service(server);
return server;
fail:
gatt_db_unref(server->db);
bt_att_unref(server->att);
free(server);
return NULL;
}
static void server_destroy(struct server *server)
{
bt_gatt_server_unref(server->gatt);
gatt_db_unref(server->db);
}
static int l2cap_le_att_listen_and_accept(bdaddr_t *src, int sec,
uint8_t src_type)
{
int sk, nsk, i;
struct sockaddr_l2 srcaddr, addr;
socklen_t optlen;
struct bt_security btsec;
char ba[18];
sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
if (sk < 0) {
perror("Failed to create L2CAP socket");
return -1;
}
/* Set up source address */
memset(&srcaddr, 0, sizeof(srcaddr));
srcaddr.l2_family = AF_BLUETOOTH;
srcaddr.l2_cid = htobs(ATT_CID);
srcaddr.l2_bdaddr_type = src_type;
bacpy(&srcaddr.l2_bdaddr, src);
PRLOG("\n");
if (bind(sk, (struct sockaddr *) &srcaddr, sizeof(srcaddr)) < 0) {
perror("Failed to bind L2CAP socket");
goto fail;
}
/* Set the security level */
memset(&btsec, 0, sizeof(btsec));
btsec.level = sec;
if (setsockopt(sk, SOL_BLUETOOTH, BT_SECURITY, &btsec,
sizeof(btsec)) != 0) {
fprintf(stderr, "Failed to set L2CAP security level\n");
goto fail;
}
if (listen(sk, 10) < 0) {
perror("Listening on socket failed");
goto fail;
}
PRLOG("Started listening on ATT channel. Waiting for connections\n");
memset(&addr, 0, sizeof(addr));
optlen = sizeof(addr);
nsk = accept(sk, (struct sockaddr *) &addr, &optlen);
if (nsk < 0) {
perror("Accept failed");
goto fail;
}
ba2str(&addr.l2_bdaddr, ba);
PRLOG("Connect from %s\n", ba);
close(sk);
return nsk;
fail:
close(sk);
return -1;
}
static void signal_cb(int signum, void *user_data)
{
switch (signum) {
case SIGINT:
case SIGTERM:
mainloop_quit();
break;
default:
break;
}
}
static void send_cmd(int cmd, void *params, int params_len)
{
struct hci_request rq;
uint8_t status;
int dd, ret, hdev;
hdev = hci_get_route(NULL);
dd = hci_open_dev(hdev);
if (dd < 0) {
perror("Could not open device");
exit(1);
}
memset(&rq, 0, sizeof(rq));
rq.ogf = OGF_LE_CTL;
rq.ocf = cmd;
rq.cparam = params;
rq.clen = params_len;
rq.rparam = &status;
rq.rlen = 1;
ret = hci_send_req(dd, &rq, 1000);
done:
hci_close_dev(dd);
if (ret < 0) {
fprintf(stderr, "Can't send cmd 0x%x to hci%d: %s (%d)\n", cmd,
hdev, strerror(errno), errno);
exit(1);
}
if (status) {
fprintf(stderr,
"LE cmd 0x%x on hci%d returned status %d\n", cmd,
hdev, status);
exit(1);
}
}
static void clear_adv_set(void)
{
int temp = 10;
send_cmd(BT_HCI_CMD_LE_CLEAR_ADV_SETS, &temp, 1);
}
static void set_adv_data(void)
{
struct bt_hci_cmd_le_set_adv_data param;
#ifdef DUEROS
uint8_t data[] = {0x02, 0x1, 0x01, 0x03, 0x03, 0x11, 0x11, 0x0c, 0x09, 0x44, 0x75, 0x65, 0x72, 0x4f, 0x53, 0x5f, 0x34, 0x30, 0x38, 0x32};
#else
//complete local name: 0x04, 0x09, 0x41, 0x4d, 0x4c (AML)
uint8_t data[] = {0x02, 0x1, 0x06, 0x03, 0x03, 0x0a, 0x18, 0x04, 0x09, 0x41, 0x4d, 0x4c, 0x08, 0x1b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
// advertise public mac addr
memcpy(data + sizeof(data) - 6, hdi.bdaddr.b, 6);
#endif
memset(&param, 0, sizeof(param));
param.len = sizeof(data);
memcpy(param.data, data , param.len);
send_cmd(BT_HCI_CMD_LE_SET_ADV_DATA, (void *)&param, sizeof(param));
}
static void set_adv_response(void)
{
struct bt_hci_cmd_le_set_scan_rsp_data param;
//clear response
memset(&param, 0, sizeof(param));
send_cmd(BT_HCI_CMD_LE_SET_SCAN_RSP_DATA, (void *)&param, sizeof(param));
}
static void set_adv_parameters(void)
{
struct bt_hci_cmd_le_set_adv_parameters param;
#if 1
struct bt_hci_cmd_le_set_random_address r_bddr;
memcpy(r_bddr.addr, hdi.bdaddr.b, 6);
r_bddr.addr[0] += 0x04;
r_bddr.addr[1] += 0x04;
send_cmd(BT_HCI_CMD_LE_SET_RANDOM_ADDRESS, (void *)&r_bddr, sizeof(r_bddr));
#endif
param.min_interval = cpu_to_le16(0x0020);
param.max_interval = cpu_to_le16(0x0020);
param.type = 0x00; /* connectable no-direct advertising */
param.own_addr_type = 0x01; /* Use random address */
//param.own_addr_type = 0x00; /* Use public address */
param.direct_addr_type = 0x00;
memset(param.direct_addr, 0, 6);
param.channel_map = 0x07;
param.filter_policy = 0x00;
send_cmd(BT_HCI_CMD_LE_SET_ADV_PARAMETERS, (void *)&param, sizeof(param));
}
static void set_adv_enable(int enable)
{
struct bt_hci_cmd_le_set_adv_enable param;
if (enable != 0 && enable != 1) {
PRLOG("%s: invalid arg: %d\n", __func__, enable);
return;
}
param.enable = enable;
send_cmd(BT_HCI_CMD_LE_SET_ADV_ENABLE, (void *)&param, sizeof(param));
}
void ble_init(void)
{
set_adv_enable(0);
set_adv_data();
set_adv_parameters();
set_adv_response();
set_adv_enable(1);
}
void hci_dev_init(void)
{
/* Open HCI socket */
if ((ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0) {
perror("Can't open HCI socket.");
exit(1);
}
hdi.dev_id = 0;
if (ioctl(ctl, HCIGETDEVINFO, (void *) &hdi)) {
perror("Can't get device info");
exit(1);
}
}
static void *check_wifi_status(void *user_data)
{
bool result;
uint8_t status = 0;
FILE *fd;
int ret;
#ifdef DUEROS
int i;
struct server *rtk_ble_server;
char socket_recv_bf[256] = {0};
rtk_ble_server = (struct server *)user_data;
#endif
while (1) {
#ifdef DUEROS
rtk_socket_rev_len = recv(rtk_ble_sk, socket_rev, 256, 0);
strncpy(socket_recv_bf, socket_rev, rtk_socket_rev_len);
PRLOG ("msg from duerOS: %s, len = %d\n", socket_rev, rtk_socket_rev_len);
if (rtk_socket_rev_len > 0) {
if (rtk_socket_rev_len > 20) {
for (i = 0 ; i < rtk_socket_rev_len / 20 ; i++ )
bt_gatt_server_send_notification(rtk_ble_server->gatt, rtk_ble_server->chara_handle, socket_rev + i * 20, 20);
if (rtk_socket_rev_len % 20)
bt_gatt_server_send_notification(rtk_ble_server->gatt, rtk_ble_server->chara_handle, socket_rev + 20 * i, rtk_socket_rev_len - 20 * i);
} else
bt_gatt_server_send_notification(rtk_ble_server->gatt, rtk_ble_server->chara_handle, socket_rev, rtk_socket_rev_len);
}
memset(socket_recv_bf, 0, sizeof(socket_recv_bf));
#else
if (wifi_configured) {
PRLOG("wifi configured\n");
system("sh /var/www/cgi-bin/wifi/wifi_tool.sh");
fd = fopen(wifi_status_file, "r+");
if (!fd) {
PRLOG("read wifi status file error\n");
return NULL;
}
ret = fread(&status, 1, 1, fd);
if (ret == 1) {
if (!strncmp(&status, &wifi_success, 1)) {
wifi_status = 1;
PRLOG("wifi setup success, and then exit ble mode\n");
//sleep(5);
//system("sh /usr/bin/bluez_tool.sh reset &");
exit(0);
} else {
wifi_status = 2;
PRLOG("status not ok: %c , configure wifi fail!\n", status);
}
}
fclose(fd);
status = 0;
wifi_configured = 0;
}
sleep(2);
#endif
}
PRLOG("%s thread exit\n", __func__);
}
int main(int argc, char *argv[])
{
bdaddr_t src_addr;
int fd, bytes;
int sec = BT_SECURITY_LOW;
char msg[64];
uint8_t src_type = BDADDR_LE_PUBLIC;
sigset_t mask;
if (argc > 1) {
if (strcmp(argv[1], "-v") == 0)
verbose = true;
}
#ifdef DUEROS
//create socket server
memcpy(sk_handle.sock_path, socket_path, strlen(socket_path));
setup_socket_server(&sk_handle);
while (1) {
begin:
rtk_ble_sk = accpet_client(&sk_handle);
if (rtk_ble_sk < 0) {
PRLOG("accept client fail\n");
sleep(1);
continue;
}
PRLOG ("accept done : %d\n", rtk_ble_sk);
memset(msg, 0, sizeof(msg));
bytes = recv(rtk_ble_sk, msg, sizeof(msg), 0);
if (bytes == 0 ) {
PRLOG("client leaved, waiting for reconnect");
goto begin;
}
PRLOG("bytes = %d, msg: %s\n", bytes, msg);
if (strncmp(msg, "aml_ble_setup_wifi", 18) == 0) {
PRLOG("aml_ble_setup_wifi connected\n");
break;
}
}
#endif
hci_dev_init();
ble_init();
bacpy(&src_addr, BDADDR_ANY);
fd = l2cap_le_att_listen_and_accept(&src_addr, sec, src_type);
if (fd < 0) {
fprintf(stderr, "Failed to accept L2CAP ATT connection\n");
return EXIT_FAILURE;
}
mainloop_init();
server = server_create(fd);
if (!server) {
close(fd);
return EXIT_FAILURE;
}
pthread_create(&thread_id, NULL, check_wifi_status, server);
PRLOG("Running GATT server\n");
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGTERM);
mainloop_set_signal(&mask, signal_cb, NULL, NULL);
mainloop_run();
PRLOG("Shutting down...\n");
server_destroy(server);
pthread_cancel(thread_id);
return EXIT_SUCCESS;
}