Created
May 15, 2019 13:30
-
-
Save pedrominatel/c913a732d4930d4ce81473f4315c3cf2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (C) 2014 BlueKitchen GmbH | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions | |
* are met: | |
* | |
* 1. Redistributions of source code must retain the above copyright | |
* notice, this list of conditions and the following disclaimer. | |
* 2. Redistributions in binary form must reproduce the above copyright | |
* notice, this list of conditions and the following disclaimer in the | |
* documentation and/or other materials provided with the distribution. | |
* 3. Neither the name of the copyright holders nor the names of | |
* contributors may be used to endorse or promote products derived | |
* from this software without specific prior written permission. | |
* 4. Any redistribution, use, or modification is done solely for | |
* personal benefit and not for any commercial purpose or for | |
* monetary gain. | |
* | |
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS | |
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS | |
* RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS | |
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF | |
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
* SUCH DAMAGE. | |
* | |
* Please inquire about commercial licensing options at | |
* contact@bluekitchen-gmbh.com | |
* | |
*/ | |
#define __BTSTACK_FILE__ "spp_counter.c" | |
// ***************************************************************************** | |
/* EXAMPLE_START(spp_counter): SPP Server - Heartbeat Counter over RFCOMM | |
* | |
* @text The Serial port profile (SPP) is widely used as it provides a serial | |
* port over Bluetooth. The SPP counter example demonstrates how to setup an SPP | |
* service, and provide a periodic timer over RFCOMM. | |
*/ | |
// ***************************************************************************** | |
#include <inttypes.h> | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include "btstack.h" | |
#define RFCOMM_SERVER_CHANNEL 1 | |
#define HEARTBEAT_PERIOD_MS 1000 | |
static char lineBuffer[30]; | |
static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); | |
static uint16_t rfcomm_channel_id; | |
static uint8_t spp_service_buffer[150]; | |
static btstack_packet_callback_registration_t hci_event_callback_registration; | |
/* @section SPP Service Setup | |
*s | |
* @text To provide an SPP service, the L2CAP, RFCOMM, and SDP protocol layers | |
* are required. After setting up an RFCOMM service with channel nubmer | |
* RFCOMM_SERVER_CHANNEL, an SDP record is created and registered with the SDP server. | |
* Example code for SPP service setup is | |
* provided in Listing SPPSetup. The SDP record created by function | |
* spp_create_sdp_record consists of a basic SPP definition that uses the provided | |
* RFCOMM channel ID and service name. For more details, please have a look at it | |
* in \path{src/sdp_util.c}. | |
* The SDP record is created on the fly in RAM and is deterministic. | |
* To preserve valuable RAM, the result could be stored as constant data inside the ROM. | |
*/ | |
/* LISTING_START(SPPSetup): SPP service setup */ | |
static void spp_service_setup(void){ | |
// register for HCI events | |
hci_event_callback_registration.callback = &packet_handler; | |
hci_add_event_handler(&hci_event_callback_registration); | |
l2cap_init(); | |
rfcomm_init(); | |
rfcomm_register_service(packet_handler, RFCOMM_SERVER_CHANNEL, 0xffff); // reserved channel, mtu limited by l2cap | |
// init SDP, create record for SPP and register with SDP | |
sdp_init(); | |
memset(spp_service_buffer, 0, sizeof(spp_service_buffer)); | |
spp_create_sdp_record(spp_service_buffer, 0x10001, RFCOMM_SERVER_CHANNEL, "SPP Counter"); | |
sdp_register_service(spp_service_buffer); | |
printf("SDP service record size: %u\n", de_get_len(spp_service_buffer)); | |
} | |
/* LISTING_END */ | |
/* @section Bluetooth Logic | |
* @text The Bluetooth logic is implemented within the | |
* packet handler, see Listing SppServerPacketHandler. In this example, | |
* the following events are passed sequentially: | |
* - BTSTACK_EVENT_STATE, | |
* - HCI_EVENT_PIN_CODE_REQUEST (Standard pairing) or | |
* - HCI_EVENT_USER_CONFIRMATION_REQUEST (Secure Simple Pairing), | |
* - RFCOMM_EVENT_INCOMING_CONNECTION, | |
* - RFCOMM_EVENT_CHANNEL_OPENED, | |
* - RFCOMM_EVETN_CAN_SEND_NOW, and | |
* - RFCOMM_EVENT_CHANNEL_CLOSED | |
*/ | |
/* @text Upon receiving HCI_EVENT_PIN_CODE_REQUEST event, we need to handle | |
* authentication. Here, we use a fixed PIN code "0000". | |
* | |
* When HCI_EVENT_USER_CONFIRMATION_REQUEST is received, the user will be | |
* asked to accept the pairing request. If the IO capability is set to | |
* SSP_IO_CAPABILITY_DISPLAY_YES_NO, the request will be automatically accepted. | |
* | |
* The RFCOMM_EVENT_INCOMING_CONNECTION event indicates an incoming connection. | |
* Here, the connection is accepted. More logic is need, if you want to handle connections | |
* from multiple clients. The incoming RFCOMM connection event contains the RFCOMM | |
* channel number used during the SPP setup phase and the newly assigned RFCOMM | |
* channel ID that is used by all BTstack commands and events. | |
* | |
* If RFCOMM_EVENT_CHANNEL_OPENED event returns status greater then 0, | |
* then the channel establishment has failed (rare case, e.g., client crashes). | |
* On successful connection, the RFCOMM channel ID and MTU for this | |
* channel are made available to the heartbeat counter. After opening the RFCOMM channel, | |
* the communication between client and the application | |
* takes place. In this example, the timer handler increases the real counter every | |
* second. | |
* | |
* RFCOMM_EVENT_CAN_SEND_NOW indicates that it's possible to send an RFCOMM packet | |
* on the rfcomm_cid that is include | |
*/ | |
/* LISTING_START(SppServerPacketHandler): SPP Server - Heartbeat Counter over RFCOMM */ | |
static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ | |
UNUSED(channel); | |
/* LISTING_PAUSE */ | |
bd_addr_t event_addr; | |
uint8_t rfcomm_channel_nr; | |
uint16_t mtu; | |
int i; | |
switch (packet_type) { | |
case HCI_EVENT_PACKET: | |
switch (hci_event_packet_get_type(packet)) { | |
/* LISTING_RESUME */ | |
case HCI_EVENT_PIN_CODE_REQUEST: | |
// inform about pin code request | |
printf("Pin code request - using '0000'\n"); | |
hci_event_pin_code_request_get_bd_addr(packet, event_addr); | |
gap_pin_code_response(event_addr, "0000"); | |
break; | |
case HCI_EVENT_USER_CONFIRMATION_REQUEST: | |
// ssp: inform about user confirmation request | |
printf("SSP User Confirmation Request with numeric value '%06"PRIu32"'\n", little_endian_read_32(packet, 8)); | |
printf("SSP User Confirmation Auto accept\n"); | |
break; | |
case RFCOMM_EVENT_INCOMING_CONNECTION: | |
// data: event (8), len(8), address(48), channel (8), rfcomm_cid (16) | |
rfcomm_event_incoming_connection_get_bd_addr(packet, event_addr); | |
rfcomm_channel_nr = rfcomm_event_incoming_connection_get_server_channel(packet); | |
rfcomm_channel_id = rfcomm_event_incoming_connection_get_rfcomm_cid(packet); | |
printf("RFCOMM channel %u requested for %s\n", rfcomm_channel_nr, bd_addr_to_str(event_addr)); | |
rfcomm_accept_connection(rfcomm_channel_id); | |
break; | |
case RFCOMM_EVENT_CHANNEL_OPENED: | |
// data: event(8), len(8), status (8), address (48), server channel(8), rfcomm_cid(16), max frame size(16) | |
if (rfcomm_event_channel_opened_get_status(packet)) { | |
printf("RFCOMM channel open failed, status %u\n", rfcomm_event_channel_opened_get_status(packet)); | |
} else { | |
rfcomm_channel_id = rfcomm_event_channel_opened_get_rfcomm_cid(packet); | |
mtu = rfcomm_event_channel_opened_get_max_frame_size(packet); | |
printf("RFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u\n", rfcomm_channel_id, mtu); | |
} | |
break; | |
case RFCOMM_EVENT_CAN_SEND_NOW: | |
rfcomm_send(rfcomm_channel_id, (uint8_t*) lineBuffer, strlen(lineBuffer)); | |
break; | |
/* LISTING_PAUSE */ | |
case RFCOMM_EVENT_CHANNEL_CLOSED: | |
printf("RFCOMM channel closed\n"); | |
rfcomm_channel_id = 0; | |
break; | |
default: | |
break; | |
} | |
break; | |
case RFCOMM_DATA_PACKET: | |
printf("Recebido: "); | |
for (i=0;i<size;i++){ | |
putchar(packet[i]); | |
} | |
if (rfcomm_channel_id){ | |
sprintf(lineBuffer, "Loopback %s\n", packet); | |
rfcomm_request_can_send_now_event(rfcomm_channel_id); | |
} | |
break; | |
default: | |
break; | |
} | |
/* LISTING_RESUME */ | |
} | |
/* LISTING_END */ | |
int btstack_main(int argc, const char * argv[]); | |
int btstack_main(int argc, const char * argv[]){ | |
(void)argc; | |
(void)argv; | |
spp_service_setup(); | |
gap_discoverable_control(1); | |
gap_ssp_set_io_capability(SSP_IO_CAPABILITY_DISPLAY_YES_NO); | |
gap_set_local_name("ESP32-Serial"); | |
// turn on! | |
hci_power_control(HCI_POWER_ON); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment