Skip to content

Instantly share code, notes, and snippets.

@shabaz123
Created October 8, 2023 22:31
Show Gist options
  • Save shabaz123/a3fc517ac8ba5cf8bd3f776da1055ef3 to your computer and use it in GitHub Desktop.
Save shabaz123/a3fc517ac8ba5cf8bd3f776da1055ef3 to your computer and use it in GitHub Desktop.
BLE code
/************************************************************************
* ble_handler.cpp
* shabaz - oct 2023
* this file encapsulates the BLE related functions used in the project
************************************************************************/
// includes
#include "ble_handler.h"
#include "config_gatt.h"
#include "btstack.h"
#include "pico/cyw43_arch.h"
#include "pico/btstack_cyw43.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// ************************ defines ***********************************
ble_rx_t ble_rx; // contains received data from remote BLE device
// ********************* global variables *****************************
// Advertisement Data, contains Flags, and Advertised Name
// First byte is the number of following bytes, and the second byte is the type
// type 0x01 = Flags
// type 0x09 = Name
const uint8_t adv_data[] = {
// Flags general discoverable, BR/EDR not supported
0x02, 0x01, 0x06,
// Name
0x0b, 0x09, 'E', 'a', 's', 'y', 'A', 'c', 'c', 'e', 's', 's'
};
const uint8_t adv_data_len = sizeof(adv_data);
const char * test_string = "Test response";
// Used for notifications
uint16_t NotifyState = 0;
hci_con_handle_t con_handle = HCI_CON_HANDLE_INVALID;
// ********************** function prototypes **************************
static uint16_t att_read_callback(hci_con_handle_t con_handle, uint16_t att_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size);
static int att_write_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size);
void att_server_handle_can_send_now(void);
static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
// ************************ functions definitions **********************
//CYW43438 driver initialization
int ble_chip_init(void) {
int ret = 0;
if (cyw43_arch_init()) {
printf("ERROR - failed to initialise cyw43_arch!\n");
ret = -1;
}
return (ret);
}
static void ble_setup(void){
l2cap_init();
// setup SM: Display only
sm_init();
// setup ATT server
att_server_init(profile_data, att_read_callback, att_write_callback);
// register for ATT events
att_server_register_packet_handler(packet_handler);
// setup advertisements
uint16_t adv_int_min = 0x0030;
uint16_t adv_int_max = 0x0030;
uint8_t adv_type = 0;
bd_addr_t null_addr;
memset(null_addr, 0, 6);
gap_advertisements_set_params(adv_int_min, adv_int_max, adv_type, 0, null_addr, 0x07, 0x00);
gap_advertisements_set_data(adv_data_len, (uint8_t*) adv_data);
gap_advertisements_enable(1);
}
// read callback (i.e. remote device is attempting to read from us)
static uint16_t att_read_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){
UNUSED(connection_handle);
// useless code when ENABLE_ATT_DELAYED_RESPONSE is not defined - but avoids built errors
if (att_handle == ATT_CHARACTERISTIC_0000CC01_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE){
printf("Remote read request for 0000CC01\n");
return att_read_callback_handle_blob((const uint8_t *)test_string, (uint16_t) strlen(test_string), offset, buffer, buffer_size);
}
if (att_handle == ATT_CHARACTERISTIC_0000CC02_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE){
printf("Remote read request for 0000CC02\n");
return att_read_callback_handle_blob((const uint8_t *)test_string, (uint16_t) strlen(test_string), offset, buffer, buffer_size);
}
return 0;
}
// write callback (i.e. remote device has written to one of our attributes)
static int att_write_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size){
UNUSED(transaction_mode);
UNUSED(offset);
UNUSED(buffer_size);
UNUSED(connection_handle);
NotifyState = little_endian_read_16(buffer, 0) == GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION;
if (NotifyState) {
// store the connection handle
con_handle = connection_handle;
}
if (att_handle == ATT_CHARACTERISTIC_0000CC01_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE) {
printf("Remote write request for 0000CC01, value: ");
printf_hexdump(buffer, buffer_size);
printf("length: %d\n", buffer_size);
if (ble_rx.status == STATUS_NO_DATA) {
memcpy(ble_rx.data, buffer, buffer_size);
ble_rx.len = buffer_size;
ble_rx.status = STATUS_NEW_DATA;
}
else {
// hmmm, the previous data has not been consumed. This should not happen.
// throw away the new data. Not ideal, but will do for now.
printf("ERROR: ble_rx.status is not STATUS_NO_DATA, delay in consumption?\n");
}
return 0;
}
if (att_handle == ATT_CHARACTERISTIC_0000CC02_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE) {
printf("Remote write request for 0000CC02, value: ");
printf_hexdump(buffer, buffer_size);
printf("length: %d\n", buffer_size);
// ignore the written data for now. We only want to use this characteristic for Notify
if (NotifyState) {
printf("Notify enabled\n");
}
return 0;
}
return 0;
}
static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
UNUSED(channel);
UNUSED(size);
if (packet_type != HCI_EVENT_PACKET) return;
switch (hci_event_packet_get_type(packet)) {
case HCI_EVENT_DISCONNECTION_COMPLETE:
NotifyState = 0;
break;
case ATT_EVENT_CAN_SEND_NOW:
att_server_notify(con_handle, ATT_CHARACTERISTIC_0000CC02_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE, (uint8_t*) "Bob", 3);
break;
default:
break;
}
}
// send a Notification
void
ble_send_notification(char* data)
{
if (NotifyState) {
att_server_handle_can_send_now();
}
}
int blestack_main(void)
{
ble_setup();
hci_power_control(HCI_POWER_ON); // turn on!
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment