blob: 0beee2a33e88dc57f22e9e544dbaa7eb5d2464d2 [file] [log] [blame]
/*
* Copyright (c) 2015-2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/types.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/kernel.h>
#include <zephyr/settings/settings.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/hci.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include <gatt/services.h>
#include "edtt_driver.h"
#include "bs_tracing.h"
#include "commands.h"
#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
static const struct bt_data ad[] = {
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
BT_DATA_BYTES(BT_DATA_UUID16_ALL,
BT_UUID_16_ENCODE(BT_UUID_HRS_VAL),
BT_UUID_16_ENCODE(BT_UUID_BAS_VAL),
BT_UUID_16_ENCODE(BT_UUID_CTS_VAL)),
BT_DATA_BYTES(BT_DATA_UUID128_ALL,
0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12,
0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12),
};
static const struct bt_data sd[] = {
BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
};
static int service_set;
static void connected(struct bt_conn *conn, uint8_t err)
{
if (err) {
printk("Connection failed (err %u)\n", err);
} else {
printk("Connected\n");
}
}
static void disconnected(struct bt_conn *conn, uint8_t reason)
{
printk("Disconnected (reason 0x%02x)\n", reason);
}
static void security_changed(struct bt_conn *conn, bt_security_t level,
enum bt_security_err err)
{
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
printk("Security changed: %s level %u\n", addr, level);
}
BT_CONN_CB_DEFINE(conn_callbacks) = {
.connected = connected,
.disconnected = disconnected,
.security_changed = security_changed,
};
static void service_setup(int set)
{
if (set == service_set) {
printk("Ignored request to change GATT services set to #%d - "
"already selected!\n", set);
return;
}
switch (service_set) {
case 0:
break;
case 1:
service_c_2_1_remove();
service_f_1_remove();
service_c_1_1_remove();
service_b_5_1_remove();
service_b_2_1_remove();
service_b_1_1_remove();
service_b_3_1_remove();
service_b_4_1_remove();
service_a_1_remove();
service_d_1_remove();
break;
case 2:
service_e_2_remove();
service_b_5_2_remove();
service_b_2_2_remove();
service_b_3_2_remove();
service_a_2_remove();
service_b_1_2_remove();
service_d_2_remove();
service_b_4_2_remove();
service_c_1_2_remove();
service_c_2_2_remove();
break;
case 3:
service_e_3_remove();
service_c_2_3_remove();
service_b_2_3_remove();
service_c_1_3_remove();
service_a_3_remove();
service_b_3_3_remove();
service_b_4_3_remove();
service_b_5_3_remove();
service_d_3_remove();
service_b_1_3_remove();
break;
default:
break;
}
switch (set) {
case 0:
break;
case 1:
service_d_1_init();
service_a_1_init();
service_b_4_1_init();
service_b_3_1_init();
service_b_1_1_init();
service_b_2_1_init();
service_b_5_1_init();
service_c_1_1_init();
service_f_1_init();
service_c_2_1_init();
break;
case 2:
service_c_2_2_init();
service_c_1_2_init();
service_b_4_2_init();
service_d_2_init();
service_b_1_2_init();
service_a_2_init();
service_b_3_2_init();
service_b_2_2_init();
service_b_5_2_init();
service_e_2_init();
break;
case 3:
service_b_1_3_init();
service_d_3_init();
service_b_5_3_init();
service_b_4_3_init();
service_b_3_3_init();
service_a_3_init();
service_c_1_3_init();
service_b_2_3_init();
service_c_2_3_init();
service_e_3_init();
break;
default:
break;
}
service_set = set;
printk("Switched to GATT services set to #%d\n", set);
}
static void service_notify(void)
{
switch (service_set) {
case 0:
break;
case 1:
service_b_3_1_value_v6_notify();
break;
case 2:
service_b_3_2_value_v6_notify();
break;
case 3:
service_b_3_3_value_v6_notify();
break;
default:
break;
}
}
static void service_indicate(void)
{
switch (service_set) {
case 0:
break;
case 1:
break;
case 2:
service_b_3_2_value_v6_indicate();
break;
case 3:
service_b_3_3_value_v6_indicate();
break;
default:
break;
}
}
static void bt_ready(int err)
{
if (err) {
printk("Bluetooth init failed (err %d)\n", err);
return;
}
printk("Bluetooth initialized\n");
service_setup(1);
printk("GATT Services initialized\n");
if (IS_ENABLED(CONFIG_SETTINGS)) {
settings_load();
}
err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd,
ARRAY_SIZE(sd));
if (err) {
printk("Advertising failed to start (err %d)\n", err);
return;
}
printk("Advertising successfully started\n");
}
static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey)
{
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
printk("Passkey for %s: %06u\n", addr, passkey);
}
static void auth_cancel(struct bt_conn *conn)
{
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
printk("Pairing cancelled: %s\n", addr);
}
static struct bt_conn_auth_cb auth_cb_display = {
.passkey_display = auth_passkey_display,
.passkey_entry = NULL,
.cancel = auth_cancel,
};
/**
* @brief Clean out excess bytes from the input buffer
*/
static void read_excess_bytes(uint16_t size)
{
if (size > 0) {
uint8_t buffer[size];
edtt_read((uint8_t *)buffer, size, EDTTT_BLOCK);
printk("command size wrong! (%u extra bytes removed)", size);
}
}
/**
* @brief Switch GATT Service Set
*/
static void switch_service_set(uint16_t size)
{
uint16_t response = sys_cpu_to_le16(CMD_GATT_SERVICE_SET_RSP);
uint8_t set;
if (size > 0) {
edtt_read((uint8_t *)&set, sizeof(set), EDTTT_BLOCK);
service_setup((int)set);
size -= sizeof(set);
}
read_excess_bytes(size);
size = 0;
edtt_write((uint8_t *)&response, sizeof(response), EDTTT_BLOCK);
edtt_write((uint8_t *)&size, sizeof(size), EDTTT_BLOCK);
}
/**
* @brief Send Notifications from GATT Service Set
*/
static void handle_service_notify(uint16_t size)
{
uint16_t response = sys_cpu_to_le16(CMD_GATT_SERVICE_NOTIFY_RSP);
service_notify();
read_excess_bytes(size);
size = 0;
edtt_write((uint8_t *)&response, sizeof(response), EDTTT_BLOCK);
edtt_write((uint8_t *)&size, sizeof(size), EDTTT_BLOCK);
}
/**
* @brief Send Indications from GATT Service Set
*/
static void handle_service_indicate(uint16_t size)
{
uint16_t response = sys_cpu_to_le16(CMD_GATT_SERVICE_INDICATE_RSP);
service_indicate();
read_excess_bytes(size);
size = 0;
edtt_write((uint8_t *)&response, sizeof(response), EDTTT_BLOCK);
edtt_write((uint8_t *)&size, sizeof(size), EDTTT_BLOCK);
}
void main(void)
{
int err;
uint16_t command;
uint16_t size;
err = bt_enable(bt_ready);
if (err) {
printk("Bluetooth init failed (err %d)\n", err);
return;
}
bt_conn_auth_cb_register(&auth_cb_display);
/**
* Initialize and start EDTT system
*/
#if defined(CONFIG_ARCH_POSIX)
enable_edtt_mode();
set_edtt_autoshutdown(true);
#endif
edtt_start();
/* Implement notification. At the moment there is no suitable way
* of starting delayed work so we do it here
*/
while (1) {
/**
* Wait for a command to arrive - then read and execute command
*/
edtt_read((uint8_t *)&command, sizeof(command), EDTTT_BLOCK);
command = sys_le16_to_cpu(command);
edtt_read((uint8_t *)&size, sizeof(size), EDTTT_BLOCK);
size = sys_le16_to_cpu(size);
bs_trace_raw_time(4, "command 0x%04X received (size %u)\n",
command, size);
switch (command) {
case CMD_GATT_SERVICE_SET_REQ:
switch_service_set(size);
break;
case CMD_GATT_SERVICE_NOTIFY_REQ:
handle_service_notify(size);
break;
case CMD_GATT_SERVICE_INDICATE_REQ:
handle_service_indicate(size);
break;
default:
break;
}
}
}