728x90

Nomenclature

 

Active Peripheral Broadcast(APB) The logical transport that is used to transport L2CAP user traffic and some kinds of LMP traffic to all active devices in the piconet over the BR/EDR Controller. See Section 3.5.4.4
Ad Hoc Network A network typically created in a spontaneous manner. An ad hoc network requires no formal infrastructure and is limited in temporal and spatial extent.
Advertiser A Bluetooth Low Energy device that broadcasts advertising packets during advertising events on advertising channels
Advertising event A series of between one and three advertising packets on different advertising physical channels sent by an advertiser.
Advertising Packet A packet containing an advertising PDU. See [Vol 6] Part B, Section 2.3.1
Angle of Arrival (AoA) Angle of Arrival is the relative direction at which a propagating RF wave that was transmitted by a single antenna is incident on an antenna array.
Angle of Departure (AoD) Angle of Departure is the relative direction from which a propagating RF wave that was transmitted using an antenna array is incident on another antenna.
BD_ADDR The Bluetooth Device Address, BD_ADDR, is used to identify a Bluetooth device.
Bluetooth Bluetooth is a wireless communication link, operating in the unlicensed ISM band at 2.4 GHz using a frequency hopping transceiver. It allows real-time AV and data communications between Bluetooth Hosts. The link protocol is based on time slots.
Bluetooth Baseband The part of the Bluetooth system that specifies or implements the medium access and physical layer procedures to support the exchange of real-time voice, data information streams, and ad hoc networking between Bluetooth Devices.
Bluetooth Clock A 28 bit clock internal to a BR/EDR Controller sub-system that ticks every 312.5 µs. The value of this clock defines the slot numbering and timing in the various physical channels.
Bluetooth Controller A generic term referring to a Controller.
Bluetooth Device A device that is capable of short-range wireless communications using the Bluetooth system.
Bluetooth Device Address A 48 bit address used to identify each Bluetooth device.
BR/EDR Bluetooth basic rate (BR) and enhanced data rate (EDR).
BR/EDR Controller A term referring to the Bluetooth Radio, Baseband, Link Manager, and HCI layers.
BR/EDR Piconet Physical Channel A Channel that is divided into time slots in which each slot is related to an RF hop frequency. Consecutive hops normally correspond to different RF hop frequencies and occur at a standard hop rate of 1600 hops per second. These consecutive hops follow a pseudo-random hopping sequence, hopping through a 79 RF channel set, or optionally fewer channels when Adaptive Frequency Hopping (AFH) is in use.
BR/EDR/LE Bluetooth basic rate (BR), enhanced data rate (EDR) and low energy (LE).
C-plane Control plane
Channel Either a physical channel or an L2CAP channel, depending on the context.
Channel Sounding A Bluetooth Low Energy feature that measures and distributes information that can be used to approximate distances between devices.
Channel Sounding event A group of Channel Sounding subevents that are anchored from a common LE connection event.
Channel Sounding procedure A group of Channel Sounding events that are sequenced serially for the purpose of gathering information useful for estimating the distance between two devices.
Channel Sounding step In Channel Sounding, an individual exchange between two devices.
Channel Sounding subevent A group of Channel Sounding steps that are associated with a specific coherent timing.
Connect (to service) The establishment of a connection to a service. If not already done, this also includes establishment of a physical link, logical transport, logical link and L2CAP channel.
Connectable device A BR/EDR device in range that periodically listens on its page scan physical channel and will respond to a page on that channel. An LE device that is advertising using a connectable advertising event.
Connected devices Two BR/EDR devices and with a physical link between them.
Connecting A phase in the communication between devices when a connection between the devices is being established. (Connecting phase follows after the link establishment phase is completed.)
Connection A connection between two peer applications or higher layer protocols mapped onto an L2CAP channel.
Connection establishment A procedure for creating a connection mapped onto a channel.
Connection event A series of one or more pairs of interleaving data packets sent between a Central and a Peripheral on the same physical channel.
Connectionless Peripheral Broadcast (CPB) A feature that enables a Central to broadcast information to an unlimited number of Peripherals.
Connectionless Peripheral Broadcast Receiver A Bluetooth device that receives broadcast information from a Connectionless Peripheral Broadcast Transmitter. The device is a Peripheral of the piconet.
Connectionless Peripheral Broadcast Transmitter A Bluetooth device that sends Connectionless Peripheral Broadcast messages for reception by one or more Connectionless Peripheral Broadcast receivers. The device is the Central of the piconet.
Controller A collective term referring to all of the layers below HCI.
Coverage area The area where two Bluetooth devices can exchange messages with acceptable quality and performance.
Creation of a secure connection A procedure of establishing a connection, including authentication and encryption.
Creation of a trusted relationship A procedure where the remote device is marked as a trusted device. This includes storing a common link key for future authentication, or pairing, when a link key is not available.
Device discovery A procedure for retrieving the Bluetooth Device Address, clock, and Class of Device from discoverable devices.
Discoverable device A BR/EDR device in range that periodically listens on an inquiry scan physical channel and will respond to an inquiry on that channel. An LE device in range that is advertising with a connectable or scannable advertising event with a discoverable flag set in the advertising data. This device is in the discoverable mode.
Discoverable Mode A Bluetooth device that is performing inquiry scans in BR/EDR or advertising with a discoverable or connectable advertising event with a discoverable flag set in LE.
Discovery procedure A Bluetooth device that is carrying out the inquiry procedure in BR/EDR or scanning for advertisers using a discoverable or connectable advertising event with a discoverable flag set in LE.
HCI The Host Controller interface (HCI) provides a command interface to the baseband Controller and link manager and access to hardware status and control registers. This interface provides a uniform method of accessing the Bluetooth baseband capabilities.
Host A logical entity defined as all of the layers below the non-core profiles and above the Host Controller interface (HCI); i.e., the layers specified in Volume 3. A Bluetooth Host attached to a Bluetooth Controller may communicate with other Bluetooth Hosts attached to their Controllers as well.
Initiator From the perspective of an advertising bearer, a Bluetooth Low Energy device that listens on advertising physical channels for connectable advertising events to form connections. From the perspective of Channel Sounding, the device that transmits first within a Channel Sounding step. 
Inquiring device A BR/EDR device that is carrying out the inquiry procedure. This device is performing the discovery procedure.
Inquiry A procedure where a Bluetooth device transmits inquiry messages and listens for responses in order to discover the other Bluetooth devices that are within the coverage area.
Inquiry scan A procedure where a Bluetooth device listens for inquiry messages received on its inquiry scan physical channel.
Interoperability The ability of two or more devices to exchange information and to use the information that has been exchanged.
Isochronous data Information in a stream where each information entity in the stream is bound by a time relationship to previous and successive entities.
Known device A Bluetooth device for which at least the BD_ADDR is stored.
L2CAP Logical Link Control and Adaptation Protocol
L2CAP Channel A logical connection on L2CAP level between two devices serving a single application or higher layer protocol.
L2CAP Channel establishment A procedure for establishing a logical connection on L2CAP level.
LE Bluetooth Low Energy
Link Shorthand for a logical link.
Link establishment A procedure for establishing the default ACL link and hierarchy of links and channels between devices.
Link key A secret key that is known by two devices and is used to authenticate the link.
LMP authentication An LMP level procedure for verifying the identity of a remote device.
LMP pairing A procedure that authenticates two devices and creates a common link key that can be used as a basis for a trusted relationship or a (single) secure connection.
Logical link The lowest architectural level used to offer independent data transport services to clients of the Bluetooth system.
Logical transport Shared acknowledgment protocol and link identifiers between different logical links.
Name discovery A procedure for retrieving the user-friendly name (the Bluetooth Device Name) of a connectable device.
Packet Format of aggregated bits that are transmitted on a physical channel.
Page The initial phase of the connection procedure where a device transmits a train of page messages until a response is received from the target device or a time-out occurs.
Page scan A procedure where a device listens for page messages received on its page scan physical channel.
Paging device A Bluetooth device that is carrying out the page procedure.
Paired device A Bluetooth device for which a link key has been created (either before connection establishment was requested or during connecting phase).
Passkey A 6-digit number used to authenticate connections when Secure Simple Pairing is used.
Periodic advertising synchronization information The control information describing a periodic advertisement that a Bluetooth Low Energy device uses to synchronize to the advertisement it describes.
Physical Channel Characterized by synchronized occupancy of a sequence of RF carriers by one or more devices. A number of physical channel types exist with characteristics defined for their different purposes.
Physical link A Baseband or Link Layer level connection between two devices.
Physical Transport PHY packet transmission and/or reception on an RF channel using one or more modulation schemes.
Piconet A collection of devices (up to eight devices in BR/EDR, exactly two devices in LE) occupying a shared physical channel where one of the devices is the Piconet Central and the remaining devices are connected to it.
Piconet Central The BR/EDR device in a piconet whose Bluetooth Clock and Bluetooth Device Address are used to define the piconet physical channel characteristics. The LE device in a piconet which initiates the creation of the piconet, chooses the Access Address that identifies the piconet, and transmits first in each connection event. 
Piconet Peripheral Any BR/EDR device in a piconet that is not the Piconet Central, but is connected to the Piconet Central. The LE device in a piconet which is not the Central but communicates with it.
PIN A user-friendly number that can be used to authenticate connections to a device before pairing has taken place.
Profile Broadcast Data (PBD) A logical link that carries data from a Connectionless Peripheral Broadcast Transmitter to one or more Connectionless Peripheral Broadcast Receivers.
Pseudo-Noise Bit Sequence A series of bits that are generated randomly.
Reflector In Channel Sounding, the device that transmits second within a Channel Sounding step in response to a transmission from an initiator.
Resolving List A list of records used to generate and resolve Resolvable Private Addresses. Each record contains a local Identity Resolving Key, a peer Identity Resolving Key, and a peer Identity Address.
Round-Trip Time The time it takes for a packet to travel from an originating device to a responding device and back again to the originating device.
Scanner A Bluetooth Low Energy device that listens for advertising events on the advertising physical channels.
Scatternet Two or more piconets that have one or more devices in common.
Service discovery Procedures for querying and browsing for services offered by or through another Bluetooth device.
Service Layer Protocol A protocol that uses an L2CAP channel for transporting PDUs.
Silent device A Bluetooth enabled device appears as silent to a remote device if it does not respond to inquiries made by the remote device.
Synchronization Scan Physical Channel A physical channel that enables a Peripheral to receive synchronization train packets from a Central.
Synchronization Train A series of packets transmitted on a set of fixed frequencies that deliver sufficient information for a receiving device to start receiving corresponding Connectionless Peripheral Broadcast packets or to recover the current piconet clock after missing a Coarse Clock Adjust.
Tick (BR/EDR) the time between changes of the value of the Bluetooth Clock: 312.5 µs.
U-plane User plane
Unknown device A Bluetooth device for which no information (Bluetooth Device Address, link key or other) is stored.
728x90
728x90

LIST OF ACRONYMS AND ABBREVIATIONS

 

Acronym or
abbreviation
Writing out in full Comments
8DPSK 8 phase Differential Phase Shift Keying 3 Mb/s modulation type used by Enhanced Data rate
AAD Additional Authenticated Data  
ACI Antenna Configuration Index  
ACK Acknowledge/Acknowledgment  
ACL Asynchronous Connection-oriented [logical transport] Reliable or time-bounded, bi-directional, pointto-point
ACL-C ACL Control [logical link] (LMP)  
ACL-U ACL User [logical link] (L2CAP)  
ACO Authenticated Ciphering Offset  
AD Advertising Data  
Adv_idx Advertising channel index  
ADVB LEAdvertising Broadcast  
ADVB-C LE Advertising Broadcast Control(Logical Link)  
ADVB-U LE Advertising Broadcast User Data (Logical Link)  
ADI AdvDataInfo  
AES Advanced Encryption Standard  
AES-CCM Advanced Encryption Standard - Counter with CBC-MAC  
AFH Adaptive Frequency Hopping  
AHS Adapted Hop Sequence  
AoA Angle of Arrival  
AoD Angle of Departure  
APB Active Peripheral Broadcast [logical transport] Unreliable, uni-directional broadcast to any devices synchronized with the physical channel
APB-C APB Control [logical link] (LMP)  
APB-U APB User [logical link] (L2CAP)  
ARQ Automatic Repeat Request  
ASK Amplitude Shift Keying  
ATT Attribute Protocol  
BB Baseband  
BCH Bose, Chaudhuri & Hocquenghem Type of code The persons who discovered these codes in 1959 (H) and 1960 (B&C)
BD_ADDR Bluetooth Device Address  
BER Bit Error Rate  
BIG Broadcast Isochronous Group A group of one or more time-related Broadcast Isochronous Streams
BIS Broadcast Isochronous Stream Connectionless isochronous logical transport
BT Bandwidth Time  
C Central  
C.# Conditional Any number may be used. See [Vol 1] Part E, Section 2.11  
CAC Channel Access Code  
CBC-MAC Cipher Block Chaining Message Authentication Code  
CCM Counter with CBC-MAC  
CIG Connected Isochronous Group A group of one or more time-related Connected Isochronous Streams
CIS Connected Isochronous Stream Point-to-point isochronous logical transport
CLKN Native Clock  
CLK  Central's Clock  
CLKE Estimated Clock  
CODEC COder DECoder  
COF Ciphering Offset  
CP CTEInfo Present A field in the Data Channel PDU Header to indicate the presence of the CTEInfo field
CPB Connectionless Peripheral Broadcast The logical transport enabled by the Connectionless Peripheral Broadcast feature
CRC Cyclic Redundancy Check  
CS Channel Sounding  
CS Tone Channel Sounding Tone Unmodulated carrier associated with the phase-based ranging technique
CSA Core Specification Addendum (In plural Addenda)  
CSRK Connection Signature Resolving Key  
CTE Constant Tone Extension  
CTEInfo Constant Tone Extension Information A field in the Data Channel PDU Header and the extended advertising header
CTS Clear to send  
CVSD Continuous Variable Slope Delta Modulation  
DAC Device Access Code  
DCI Default Check Initialization  
DEVM Differential Error Vector Magnitude Measure of modulation error used for Enhanced Data Rate transmitter testing
DH Data-High Rate Data packet type for high rate data  
DHK Diversifier Hiding Key  
DIAC Dedicated Inquiry Access Code  
DID (Advertising) Data ID  
DIV Diversifier  
DM Data - Medium Rate Data packet type for medium rate data
DPSK Differential Phase Shift Keying Generic description of Enhanced Data Rate modulation
DQPSK Differential Quaternary Phase Shift Keying Modulation type used by Enhanced Data Rate
DRBG Deterministic Random Bit Generator  
DTM Direct Test Mode  
DV Data Voice Data packet type for data and voice  
E Excluded See [Vol 1] Part E, Section 2.11
ECLD Early Commit Late Detect  
EDIV Encrypted Diversifier  
EDLC Early Detect Late Commit  
EDR Enhanced Data Rate  
EIR Extended Inquiry Response Host supplied information transmitted in the Inquiry Response substate
EIRP Effective Isotropic Radiated Power Equivalent power that an isotropic antenna must transmit to provide the same field power density
(e)SCO Synchronous logical link or Extended Synchronous logical link SCO or eSCO
eSCO Extended Synchronous Connection-Oriented [logical transport] Bi-directional, symmetric or asymmetric, point to-point, general regular data, limited retransmission
eSCO-S Stream eSCO (unframed) Used to support isochronous data delivered in a stream without framing
ETSI European Telecommunications Standards Institute  
FAE Fractional Frequency Offset Actuation Error  
FCC Federal Communications Commission  
FCS Frame Check Sequence  
FDMA Frequency Division Multiple Access  
FEC Forward Error Correction code  
FFO Fractional Frequency Offset  
FHS Frequency Hop Synchronization  
FHSS Frequency Hopping Spread Spectrum  
FIFO First In First Out  
FIPS Federal Information Processing Standards  
FM Frequency Modulation Modulation type
GAP Generic Access profile  
GATT Generic Attribute profile  
GFSK Gaussian Frequency Shift Keying  
GIAC General Inquiry Access Code Used for GAP General Discoverable mode and General Inquiry procedure. See Assigned Numbers.
HCI Host Controller interface  
HEC Header-Error-Check  
HID Human Interface Device  
HV High quality Voice e.g. HV1 packet  
HW Hardware  
IAC Inquiry Access Code  
IC Industry Canada  
IEC International Electrotechnical Commission  
IEEE Institute of Electrical and Electronics Engineers  
IETF Internet Engineering Task Force  
IFS Inter Frame Space  
IP Internet Protocol  
IPv4 Internet Protocol version 4  
IPv6 Internet Protocol version 6  
IQ In-phase and Quadrature  
IrDA Infra-red Data Association  
IRK Identity Resolving Key  
ISM Industrial, Scientific, Medical  
ISO International Organization for Standardization  
ISO Isochronous  
ISOAL Isochronous Adaptation Layer The layer that converts data units from the upper layer to data units in the Link Layer and vice versa
ITU International Telecommunication Union  
IUT Implementation Under Test  
IV Initialization Vector  
IV_C Initialization Vector (Central)  
IV_P Initialization Vector (Peripheral)  
L2CAP Logical Link Control and Adaptation protocol  
LAP Lower Address Part  
LC Link Controller Link Controller (or Baseband) part of the Bluetooth protocol stack. Low level Baseband protocol handler
LC Link Control [logical link] The control logical links LC and ACL-C are used at the link control level and link manager level, respectively
LE Low Energy  
LEB-C Low Energy Broadcast Control A logical link for control of Broadcast Isochronous Streams in a Broadcast Isochronous Group
LE-C Low Energy Control (link)  
LE-F Low Energy Framed A logical link for transferring framed isochronous data packets using a Connected or Broadcast Isochronous Stream logical transport
LE-S Low Energy Stream A logical link for transferring unframed isochronous data packets using a Connected or Broadcast Isochronous Stream logical transport
LE-U LE User [logical link]  
LFAE Local Frequency Actuation Error  
LFSR Linear Feedback Shift Register  
LIAC Limited Inquiry Access Code Used for GAP Limited Discoverable mode and Limited Inquiry procedure. See Assigned Numbers.
LL Link Layer  
LLID Logical Link Identifier  
LM Link Manager  
LMP Link Manager protocol For LM peer to peer communication
LR Loudness Rating  
LSB Least Significant Bit  
LSO Least Significant Octet  
LSTO Link Supervision Timeout event Controller can send LSTO event to Host
LT_ADDR Logical Transport ADDRess  
LTK Long-Term Key  
M Mandatory See [Vol 1] Part E, Section 2.11
MAC Message Authentication Code  
Mb/s Megabits (millions of bits) per second MD More Data  
MIC Message Integrity Check  
MITM Man-in-the-middle  
Msym/s Megasymbols per second  
MSB Most Significant Bit  
mSBC modified Sub Band Codec Hands-Free Profile v1.6 or later
MSC Message sequence chart  
MSO Most Significant Octet  
MTU Maximum Transmission Unit  
MWS Mobile Wireless Standards For example LTE and WiMAX
N_AP Number of Antenna Paths  
NADM Normalized Attack Detector Metric  
NAK Negative Acknowledge  
NAP Non-significant Address Part  
NESN Next Expected Sequence Number  
NIST National Institute of Standards and Technology  
O Optional See [Vol 1] Part E, Section 2.11
OBEX OBject EXchange protocol  
OCF Opcode Command Field  
OGF Opcode Group Field  
OOB Out of Band  
π/4-DQPSK π/4 Rotated Differential Quaternary Phase Shift Keying 2 Mb/s modulation type used by Enhanced Data Rate
P Peripheral  
PADVB LE Periodic Advertising Broadcast(Logical Transport)  
PAwR Periodic Advertising with Responses  
PBD Profile Broadcast Data The name of the logical link enabled by the Connectionless Peripheral Broadcast feature
PBF Packet Boundary Flag The device supports the capability to correctly handle HCI ACL Data packets
PBR Phase-Based Ranging  
PCM Pulse Coded Modulation  
PCT Phase Correction Term  
PDU Protocol Data Unit A message
PHY Physical Layer  
PIN Personal Identification Number  
PN Pseudo-random Noise  
ppm Part Per Million  
PPP Point-to-Point Protocol  
PRBS Pseudo Random Bit Sequence  
PRNG Pseudo Random Noise Generation  
PSK Phase Shift Keying Class of modulation types
ptt Packet Type Table The ptt parameter is used to select the logical transport types via LMP.
QoS Quality of Service  
RAND Random number  
RF Radio Frequency  
RFC Request For Comments  
RFCMode Retransmission and Flow Control Mode  
RFCOMM   Serial cable emulation protocol based on ETSI TS 07.10
RFU Reserved for future use  
RMS Root Mean Square  
RPA Resolvable Private Address  
RPL Reference Power Level  
RSSI Received Signal Strength Indication  
RTT Round-Trip Time  
RX Receive  
SAR Segmentation and Reassembly  
SCA Sleep Clock Accuracy  
SCO Synchronous Connection-Oriented [logical transport] Bi-directional, symmetric, point-to-point, AV channels
SCO-S Stream SCO (unframed) Used to support isochronous data delivered in a stream without framing
SDP Service Discovery protocol  
SDU Service Data Unit  
SEQN Sequential Numbering scheme  
SID (Advertising) Set ID  
SK Session Key  
SKD_C Session Key Diversifier (Central) Central portion of the Session Key Diversifier
SKD_P Session Key Diversifier (Peripheral) Peripheral portion of the Session Key Diversifier
SM Security Manager  
SMP Security Manager Protocol  
SN Sequence Number  
SNR Signal-to-Noise Ratio  
SRES Signed Response  
SRK Signature Resolving Key  
SSI Signal Strength Indication  
SSP Secure Simple Pairing  
STK Short Term Key  
SW Software  
T_FCS Time for Frequency Change Spacing  
T_FM Time for Frequency Measurement  
T_GD Time for Guard period  
T_IFS Time Inter Frame Space Time interval between consecutive packets on same channel index in the situation indicated by the suffix. See [Vol 6] Part B, Section 4.1.1.
T_IP1 Time for Interlude Period 1 (between CS packets)  
T_IP2 Time for Interlude Period 2 (between CS tones)  
T_MCES Time Minimum Connection Event Spacing Minimum time interval between connection events. See [Vol 6] Part B, Section 4.1.5.
T_MSS Time Minimum Subevent Spacing Minimum time interval between subevents in the situation indicated by the suffix. See [Vol 6] Part B, Section 4.2.2.
T_PM Time for Phase Measurement  
T_RD Time for (transmission) RampDown  
T_SY Time for synchronization sequence (CS packet)  
TCP/IP Transport Control Protocol/Internet Protocol  
TCS Telephony Control protocol Specification  
TDD Time-Division Duplex  
TDMA Time Division Multiple Access  
TK Temporary Key  
ToA Time of Arrival  
ToD Time of Departure  
ToF Time of Flight  
TX Transmit  
UAP Upper Address Part  
UART Universal Asynchronous receiver Transmitter  
UI User Interface  
ULAP Upper and Lower Address Parts  
USB Universal Serial Bus  
UTF-8 8-bit UCS/Unicode Transformation Format  
UUID Universal Unique Identifier  
728x90
728x90

CYW920719B2Q40EVB-01 EVB의 모습니다.

CYW20719를 사용하고, 앞에 9로 시작하는 것은 EVB를 나타내는 것이다.

Bluetooth BR/EDR(Classic) 그리고 BLE가 같이 동작하는 dual mode chip이다.

자세한 설명은 아래 링크에서 확인 가능하다.

https://www.infineon.com/cms/en/product/wireless-connectivity/airoc-bluetooth-le-bluetooth-multiprotocol/airoc-bluetooth-le-bluetooth/cyw20719/

 

 

SDK는 ModusToolBox를 사용하는데 Infineon community에서 받을 수 있다.

https://community.infineon.com/

ModusToolBox를 설치하고 CYW20719를 USB(to serial)를 연결하면 UART 장치가 두개 생겨야 한다.(HCI/PUART)

만약 드라이버가 제대로 잡히지 않는다면 설치경로에 있는 driver를 이용하여 직접 설치해야 할 수 있다.

C:\Infineon\Tools\ModusToolbox\tools_3.1\driver_media

SDK는 Eclipse를 기반으로 만들어져 있다.

 

File -> New -> ModusToolBox Application을 선택하면 example을 받을 수 있다.

Project Creator가 github에서 받아오는 방식인데 먼저 AIROC Bluetooth BSPs를 선택하고 CYW920719B2Q40EVB-01를 선택한다.

Classic Bluetooth에서 가장 간단히 test하는 profile로는 SPP로 많이 시작한다.

SPP는 serial 통신을 Bluetooth 구현한 것이라 data 전송 외에는 특별한 기능이 없다.

ModusToolBox 에서는 "RFCOMM Serial Port" 예제를 선택하면 된다.

 

README.md : example에 대한 설명과 define을 어떻게 사용하는지 설명

makefile : build config들이 모여있다.

cycfg_bt.cybt : SDP정보를 바꿀 수 있다.

spp.c : example 내용이 들어있다. 간단히 c file하나로 사용하는 example이다.

 

spp.c code (더보기를 누르면 전체 코드를 확인 가능)

더보기
/*
 * Copyright 2016-2022, Cypress Semiconductor Corporation (an Infineon company) or
 * an affiliate of Cypress Semiconductor Corporation.  All rights reserved.
 *
 * This software, including source code, documentation and related
 * materials ("Software") is owned by Cypress Semiconductor Corporation
 * or one of its affiliates ("Cypress") and is protected by and subject to
 * worldwide patent protection (United States and foreign),
 * United States copyright laws and international treaty provisions.
 * Therefore, you may use this Software only as provided in the license
 * agreement accompanying the software package from which you
 * obtained this Software ("EULA").
 * If no EULA applies, Cypress hereby grants you a personal, non-exclusive,
 * non-transferable license to copy, modify, and compile the Software
 * source code solely for use in connection with Cypress's
 * integrated circuit products.  Any reproduction, modification, translation,
 * compilation, or representation of this Software except as specified
 * above is prohibited without the express written permission of Cypress.
 *
 * Disclaimer: THIS SOFTWARE IS PROVIDED AS-IS, WITH NO WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, NONINFRINGEMENT, IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Cypress
 * reserves the right to make changes to the Software without notice. Cypress
 * does not assume any liability arising out of the application or use of the
 * Software or any product or circuit described in the Software. Cypress does
 * not authorize its products for use in any products where a malfunction or
 * failure of the Cypress product may reasonably be expected to result in
 * significant property damage, injury or death ("High Risk Product"). By
 * including Cypress's product in a High Risk Product, the manufacturer
 * of such system or application assumes all risk of such use and in doing
 * so agrees to indemnify Cypress against all liability.
 */

/** @file
 *
 * SPP Application for 20XXX devices.
 *
 * SPP application uses SPP profile library to establish, terminate, send and receive SPP
 * data over BR/EDR. This sample supports single a single SPP connection.
 *
 * Following compilation flags are important for testing
 *  HCI_TRACE_OVER_TRANSPORT - configures HCI traces to be routed to the WICED HCI interface
 *  WICED_BT_TRACE_ENABLE    - enables WICED_BT_TRACEs.  You can also modify makefile.mk to build
 *                             with _debug version of the library
 *  SEND_DATA_ON_INTERRUPT   - if defined, the app will send 1Meg of data on application button push
 *  SEND_DATA_ON_TIMEOUT     - if defined, the app will send 4 bytes every second while session is up
 *  LOOPBACK_DATA            - if enabled, the app sends back received data
 *
 * To demonstrate the app, work through the following steps.
 * 1. Build and download the application to the WICED board.
 * 2. Open the Bluetooth Classic and LE Profile Client Control application and open the port for WICED HCI for the device.
 *    Default baud rate configured in the application is defined by the BSP HCI_UART_DEAULT_BAUD #define,
 *    usually either 3M or 115200 depending on board UART capabilities.
 * 3. Run the BTSpy program to view protocol and application traces.
 *    See "Bluetooth Classic and LE Profile Client Control" and "BTSpy" in chip-specifc readme.txt for more information about these apps.
 * 4. On Windows 10 PCs, right click on the Bluetooth icon in the system tray and
 *    select 'Add a Bluetooth Device'. Find and pair with the spp app. That should create an incoming and an outgoing
 *    COM port on your computer. Right click on the Bluetooth icon in the system tray and
 *    select 'Open Settings', scroll down and select "More Bluetooth options" and then
 *    select the 'COM Ports' tab.
 * 5. Use application such as Term Term to open the outgoing COM port. Opening the port
 *    will create the SPP connection.
 * 6. Type any key on the terminal of the outgoing COM port, the spp application will receive the key.
 * 7. By default, (SEND_DATA_ON_INTERRUPT=1) the application sends 1 MB data to the peer application on every
 *    App button press on the WICED board.
 * 8. If desired, edit the spp.c file to configure the application to send data on a timer to the peer application by
 *    setting SEND_DATA_ON_INTERRUPT=0 and SEND_DATA_ON_TIMEOUT=1*
 *
 * Features demonstrated
 *  - Use of SPP library
 *
 *  Note: This snippet app does not support WICED HCI Control and may use transport only for tracing.
 *  If you route traces to WICED HCI UART, use ClientControl app with baud rate equal to that
 *  set in the wiced_transport_cfg_t structure below (currently set at HCI_UART_DEFAULT_BAUD, either 3 Mbps or 115200
 *  depending on the capabilities of the board used).
 */

#include "sparcommon.h"
#include "bt_types.h"
#include "wiced.h"
#include "wiced_gki.h"
#include "wiced_bt_dev.h"
#include "wiced_bt_sdp.h"
#include "wiced_bt_ble.h"
#include "wiced_bt_uuid.h"
#include "wiced_hal_nvram.h"
#include "wiced_bt_trace.h"
#include "wiced_bt_cfg.h"
#include "wiced_bt_spp.h"
#include "wiced_hci.h"
#include "wiced_timer.h"
#include "wiced_transport.h"
#include "wiced_platform.h"
#include "wiced_memory.h"
#include "string.h"
#include "wiced_bt_stack.h"
#include "wiced_bt_rfcomm.h"
#include "cycfg_sdp_db.h"
#if defined(CYW20706A2) || defined(CYW43012C0)
#include "wiced_bt_app_hal_common.h"
#endif

#if BTSTACK_VER >= 0x03000001
#include "wiced_memory.h"
#include "clock_timer.h"
#define BT_STACK_HEAP_SIZE          1024 * 6
wiced_bt_heap_t *p_default_heap   = NULL;
#endif

#define HCI_TRACE_OVER_TRANSPORT            1   // If defined HCI traces are send over transport/WICED HCI interface
// configure either SEND_DATA_ON_INTERRUPT or SEND_DATA_ON_TIMEOUT, but not both
// CYW9M2BASE-43012BT does not support SEND_DATA_ON_INTERRUPT because the platform does not have button connected to Bluetooth board.
#if defined (NO_BUTTON_SUPPORT)
#if defined(SEND_DATA_ON_INTERRUPT) && (SEND_DATA_ON_INTERRUPT==1)
#undef SEND_DATA_ON_INTERRUPT                   // disable SEND_DATA_ON_INTERRUPT is no app button
#define SEND_DATA_ON_TIMEOUT                1
#endif
#endif

//#define LOOPBACK_DATA                     1   // If defined application loops back received data

#define WICED_EIR_BUF_MAX_SIZE              264
#define SPP_NVRAM_ID                        WICED_NVRAM_VSID_START

/* Max TX packet to be sent over SPP */
#define MAX_TX_BUFFER                       1017
#define TRANS_MAX_BUFFERS                   2
#define TRANS_UART_BUFFER_SIZE              1024
#define SPP_MAX_PAYLOAD                     1007

#if SEND_DATA_ON_INTERRUPT
#include "wiced_hal_gpio.h"
#include "wiced_platform.h"

#define APP_TOTAL_DATA_TO_SEND             1000000
#define BUTTON_GPIO                         WICED_P30

#if defined(CYW43012C0)
#define WICED_PLATFORM_BUTTON_1          WICED_P00
#ifndef WICED_GPIO_BUTTON
#define WICED_GPIO_BUTTON                WICED_PLATFORM_BUTTON_1
#endif
#ifndef WICED_GPIO_BUTTON_DEFAULT_STATE
#define WICED_GPIO_BUTTON_DEFAULT_STATE  GPIO_PIN_OUTPUT_HIGH
#endif
#endif

int     app_send_offset = 0;
uint8_t app_send_buffer[SPP_MAX_PAYLOAD];
uint32_t time_start = 0;
#endif

#ifdef SEND_DATA_ON_TIMEOUT
wiced_timer_t spp_app_timer;
void app_timeout(TIMER_PARAM_TYPE arg);
#endif

/*****************************************************************************
**  Structures
*****************************************************************************/
#define SPP_RFCOMM_SCN               2

#define MAX_TX_RETRY                 30
#define TX_RETRY_TIMEOUT             100 // msec

static void         spp_connection_up_callback(uint16_t handle, uint8_t* bda);
static void         spp_connection_down_callback(uint16_t handle);
static wiced_bool_t spp_rx_data_callback(uint16_t handle, uint8_t* p_data, uint32_t data_len);
static void         spp_bt_remote_name_callback(wiced_bt_dev_remote_name_result_t *p_remote_name_result);

wiced_bt_spp_reg_t spp_reg =
{
    SPP_RFCOMM_SCN,                     /* RFCOMM service channel number for SPP connection */
    MAX_TX_BUFFER,                      /* RFCOMM MTU for SPP connection */
    spp_connection_up_callback,         /* SPP connection established */
    NULL,                               /* SPP connection establishment failed, not used because this app never initiates connection */
    NULL,                               /* SPP service not found, not used because this app never initiates connection */
    spp_connection_down_callback,       /* SPP connection disconnected */
    spp_rx_data_callback,               /* Data packet received */
};
#if BTSTACK_VER < 0x03000001
wiced_transport_buffer_pool_t*  host_trans_pool;
#endif
uint16_t                        spp_handle = 0;
wiced_timer_t                   app_tx_timer;
uint32_t                        spp_rx_bytes = 0;
uint32_t                        spp_tx_retry_count = 0;

uint8_t pincode[4] = { 0x30, 0x30, 0x30, 0x30 };

extern const wiced_bt_cfg_settings_t wiced_bt_cfg_settings;
#if BTSTACK_VER < 0x03000001
extern const wiced_bt_cfg_buf_pool_t wiced_bt_cfg_buf_pools[WICED_BT_CFG_NUM_BUF_POOLS];
#endif

#if defined WICED_BT_TRACE_ENABLE || defined HCI_TRACE_OVER_TRANSPORT
const wiced_transport_cfg_t transport_cfg =
{
    .type = WICED_TRANSPORT_UART,
    .cfg =
    {
        .uart_cfg =
        {
            .mode = WICED_TRANSPORT_UART_HCI_MODE,
            .baud_rate =  HCI_UART_DEFAULT_BAUD
        },
    },
#if BTSTACK_VER >= 0x03000001
        .heap_config =
        {
            .data_heap_size = 1024 * 4 + 1500 * 2,
            .hci_trace_heap_size = 1024 * 2,
            .debug_trace_heap_size = 1024,
        },
#else
    .rx_buff_pool_cfg =
    {
        .buffer_size  = TRANS_UART_BUFFER_SIZE,
        .buffer_count = 1
    },
#endif
    .p_status_handler    = NULL,
    .p_data_handler      = NULL,
    .p_tx_complete_cback = NULL
};
#endif

/*******************************************************************
 * Function Prototypes
 ******************************************************************/
static wiced_bt_dev_status_t app_management_callback (wiced_bt_management_evt_t event, wiced_bt_management_evt_data_t *p_event_data);
static void                  app_write_eir(void);
static int                   app_write_nvram(int nvram_id, int data_len, void *p_data);
static int                   app_read_nvram(int nvram_id, void *p_data, int data_len);

#if SEND_DATA_ON_INTERRUPT
static void                  app_tx_ack_timeout(TIMER_PARAM_TYPE param);
static void                  app_interrupt_handler(void *data, uint8_t port_pin);
#endif
#ifdef HCI_TRACE_OVER_TRANSPORT
static void                  app_trace_callback(wiced_bt_hci_trace_type_t type, uint16_t length, uint8_t* p_data);
#endif

#if defined (CYW20706A2)
extern BOOL32 wiced_hal_puart_select_uart_pads(UINT8 rxdPin, UINT8 txdPin, UINT8 ctsPin, UINT8 rtsPin);
extern wiced_result_t wiced_bt_app_init( void );
#endif

#ifndef CYW20706A2
extern uint64_t clock_SystemTimeMicroseconds64();
#else
#include "rtc.h"
uint64_t clock_SystemTimeMicroseconds64(void)
{
    tRTC_REAL_TIME_CLOCK rtcClock;
    rtc_getRTCRawClock(&rtcClock);
    // To convert 128 kHz rtc timer to milliseconds divide it by 131: //128 kHz = 128 * 1024 = 131072; to microseconds: 1000000 / 131072 = 7.62939453125 (7.63)
    return rtcClock.rtc64 * 763 / 100;
}
#endif

/*******************************************************************
 * Function Definitions
 ******************************************************************/

void buffer_report(char *msg)
{
#if BTSTACK_VER >= 0x03000001
    /*
     * Get statistics of default heap.
     * TODO: get statistics of stack heap (btu_cb.p_heap)
     */
    wiced_bt_heap_statistics_t heap_stat;

    if (wiced_bt_get_heap_statistics(p_default_heap, &heap_stat))
    {
        WICED_BT_TRACE("--- heap_size:%d ---\n", heap_stat.heap_size);
        WICED_BT_TRACE("max_single_allocation:%d max_heap_size_used:%d\n",
                        heap_stat.max_single_allocation,
                        heap_stat.max_heap_size_used);
        WICED_BT_TRACE("allocation_failure_count:%d current_largest_free_size:%d\n",
                        heap_stat.allocation_failure_count,
                        heap_stat.current_largest_free_size);
        WICED_BT_TRACE("current_num_allocations:%d current_size_allocated:%d\n",
                        heap_stat.current_num_allocations,
                        heap_stat.current_size_allocated);
        WICED_BT_TRACE("current_num_free_fragments:%d current_free_size\n",
                        heap_stat.current_num_free_fragments,
                        heap_stat.current_free_size);
    }
    else
    {
        WICED_BT_TRACE("buffer_report: wiced_bt_get_heap_statistics failed\n");
    }
#else /* !BTSTACK_VER */

    wiced_bt_buffer_statistics_t buffer_stats[5];
    wiced_result_t result;

    result = wiced_bt_get_buffer_usage (buffer_stats, sizeof(buffer_stats));

    if (result == WICED_BT_SUCCESS)
    {
        WICED_BT_TRACE("%s: pool %x %d %d/%d/%d\n", msg,
                buffer_stats[1].pool_id,
                buffer_stats[1].pool_size,
                buffer_stats[1].current_allocated_count,
                buffer_stats[1].max_allocated_count,
                buffer_stats[1].total_count);
        WICED_BT_TRACE("%s: pool %x %d %d/%d/%d\n", msg,
                buffer_stats[2].pool_id,
                buffer_stats[2].pool_size,
                buffer_stats[2].current_allocated_count,
                buffer_stats[2].max_allocated_count,
                buffer_stats[2].total_count);
    }
    else
        WICED_BT_TRACE("buffer_report: wiced_bt_get_buffer_usage failed, returned %d\n", result);
#endif
}

/*
 * Entry point to the application. Set device configuration and start Bluetooth
 * stack initialization.  The actual application initialization will happen
 * when stack reports that Bluetooth device is ready
 */
APPLICATION_START()
{
    wiced_result_t result;
    int interupt = 0, timeout = 0, loopback = 0;

#if defined WICED_BT_TRACE_ENABLE || defined HCI_TRACE_OVER_TRANSPORT
    wiced_transport_init(&transport_cfg);

#if BTSTACK_VER < 0x03000001
    // create special pool for sending data to the MCU
    host_trans_pool = wiced_transport_create_buffer_pool(TRANS_UART_BUFFER_SIZE, TRANS_MAX_BUFFERS);
#endif

    // Set the debug uart as WICED_ROUTE_DEBUG_NONE to get rid of prints
    // wiced_set_debug_uart(WICED_ROUTE_DEBUG_NONE);

    // Set to PUART to see traces on peripheral uart(puart) if platform has PUART
#ifdef NO_PUART_SUPPORT
    // wiced_set_debug_uart( WICED_ROUTE_DEBUG_TO_WICED_UART );
#else
    // wiced_set_debug_uart( WICED_ROUTE_DEBUG_TO_PUART );
#if defined (CYW20706A2)
    // wiced_hal_puart_select_uart_pads( WICED_PUART_RXD, WICED_PUART_TXD, 0, 0);
#endif
#endif

    // Set to HCI to see traces on HCI uart - default if no call to wiced_set_debug_uart()
    // wiced_set_debug_uart( WICED_ROUTE_DEBUG_TO_HCI_UART );

    // Use WICED_ROUTE_DEBUG_TO_WICED_UART to send formatted debug strings over the WICED
    // HCI debug interface to be parsed by ClientControl/BtSpy.
    wiced_set_debug_uart(WICED_ROUTE_DEBUG_TO_WICED_UART);
#endif

#if SEND_DATA_ON_INTERRUPT
    interupt = 1;
#endif
#if SEND_DATA_ON_TIMEOUT
    timeout = 1;
#endif
#if LOOPBACK_DATA
    loopback = 1;
#endif
    WICED_BT_TRACE("APP Start, interupt=%d, timeout=%d, loopback=%d\n", interupt, timeout, loopback);

#if BTSTACK_VER >= 0x03000001
    /* Create default heap */
    p_default_heap = wiced_bt_create_heap("default_heap", NULL, BT_STACK_HEAP_SIZE, NULL, WICED_TRUE);
    if (p_default_heap == NULL)
    {
        WICED_BT_TRACE("create default heap error: size %d\n", BT_STACK_HEAP_SIZE);
        return;
    }
    /* Initialize Stack and Register Management Callback */
    // Register call back and configuration with stack
    wiced_bt_stack_init(app_management_callback, &wiced_bt_cfg_settings);
#else
    /* Initialize Stack and Register Management Callback */
    // Register call back and configuration with stack
    wiced_bt_stack_init(app_management_callback, &wiced_bt_cfg_settings, wiced_bt_cfg_buf_pools);
#endif
}

/*
 * SPP application initialization is executed after Bluetooth stack initialization is completed.
 */
void application_init(void)
{
    wiced_result_t         result;

#if defined (CYW20706A2)
    /* Initialize wiced app */
    wiced_bt_app_init();

    /* Initialize the RTC block */
    rtc_init();
#endif

#if SEND_DATA_ON_INTERRUPT
#if !defined (CYW20706A2) && !defined (CYW43012C0)
    /* Configure the button available on the platform */
    wiced_platform_register_button_callback( WICED_PLATFORM_BUTTON_1, app_interrupt_handler, NULL, WICED_PLATFORM_BUTTON_RISING_EDGE);
#elif defined(CYW20706A2) || defined(CYW43012C0)
/* Initializes the GPIO driver */
    wiced_bt_app_hal_init();
	wiced_hal_gpio_configure_pin(WICED_GPIO_BUTTON, WICED_GPIO_BUTTON_SETTINGS( GPIO_EN_INT_RISING_EDGE ), WICED_GPIO_BUTTON_DEFAULT_STATE );
	wiced_hal_gpio_register_pin_for_interrupt(WICED_GPIO_BUTTON, app_interrupt_handler, NULL);
#endif // CYW20706A2 && CYW43012C0
    // init timer that we will use for the rx data flow control.
    wiced_init_timer(&app_tx_timer, app_tx_ack_timeout, 0, WICED_MILLI_SECONDS_TIMER);
#endif // SEND_DATA_ON_INTERRUPT

    app_write_eir();

#if defined (CYW20706A2)
    // Initialize RFCOMM.  We will not be using application buffer pool and will rely on the
    // stack pools configured in the wiced_bt_cfg.c
    wiced_bt_rfcomm_init(MAX_TX_BUFFER, 1);
#endif

    // Initialize SPP library
    wiced_bt_spp_startup(&spp_reg);

#ifdef HCI_TRACE_OVER_TRANSPORT
    // There is a virtual HCI interface between upper layers of the stack and
    // the controller portion of the chip with lower layers of the Bluetooth stack.
    // Register with the stack to receive all HCI commands, events and data.
    wiced_bt_dev_register_hci_trace(app_trace_callback);
#endif
    /* create SDP records */
    wiced_bt_sdp_db_init((uint8_t *)sdp_database, sdp_database_len);

    /* Allow peer to pair */
    wiced_bt_set_pairable_mode(WICED_TRUE, 0);

#if BTSTACK_VER >= 0x03000001
        // This application will always configure device connectable and discoverable
    wiced_bt_dev_set_discoverability(BTM_GENERAL_DISCOVERABLE,
                                     WICED_BT_CFG_DEFAULT_INQUIRY_SCAN_INTERVAL,
                                     WICED_BT_CFG_DEFAULT_INQUIRY_SCAN_WINDOW);

    wiced_bt_dev_set_connectability(BTM_CONNECTABLE,
                                    WICED_BT_CFG_DEFAULT_PAGE_SCAN_INTERVAL,
                                    WICED_BT_CFG_DEFAULT_PAGE_SCAN_WINDOW);
#else
    // This application will always configure device connectable and discoverable
    wiced_bt_dev_set_discoverability(BTM_GENERAL_DISCOVERABLE,
        wiced_bt_cfg_settings.br_edr_scan_cfg.inquiry_scan_interval,
        wiced_bt_cfg_settings.br_edr_scan_cfg.inquiry_scan_window);

    wiced_bt_dev_set_connectability(BTM_CONNECTABLE,
        wiced_bt_cfg_settings.br_edr_scan_cfg.page_scan_interval,
        wiced_bt_cfg_settings.br_edr_scan_cfg.page_scan_window);
#endif

#if SEND_DATA_ON_TIMEOUT
    /* Starting the app timers, seconds timer and the ms timer  */
    wiced_init_timer(&spp_app_timer, app_timeout, 0, WICED_SECONDS_PERIODIC_TIMER);
    wiced_start_timer(&spp_app_timer, 1);
#endif
}

/*
 *  Management callback receives various notifications from the stack
 */
wiced_result_t app_management_callback(wiced_bt_management_evt_t event, wiced_bt_management_evt_data_t *p_event_data)
{
    wiced_result_t                      result = WICED_BT_SUCCESS;
    wiced_bt_dev_status_t               dev_status;
    wiced_bt_dev_pairing_info_t*        p_pairing_info;
    wiced_bt_dev_encryption_status_t*   p_encryption_status;
    int                                 bytes_written, bytes_read;
    wiced_bt_power_mgmt_notification_t* p_power_mgmt_notification;

    WICED_BT_TRACE("app_management_callback %d\n", event);

    switch(event)
    {
    /* Bluetooth  stack enabled */
    case BTM_ENABLED_EVT:
        application_init();
        //WICED_BT_TRACE("Free mem:%d", cfa_mm_MemFreeBytes());
        break;

    case BTM_DISABLED_EVT:
        break;

    case BTM_PIN_REQUEST_EVT:
        WICED_BT_TRACE("remote address= %B\n", p_event_data->pin_request.bd_addr);
        wiced_bt_dev_pin_code_reply(*p_event_data->pin_request.bd_addr,result/*WICED_BT_SUCCESS*/,4, &pincode[0]);
        break;

    case BTM_USER_CONFIRMATION_REQUEST_EVT:
        /* This application always confirms peer's attempt to pair */
        wiced_bt_dev_confirm_req_reply (WICED_BT_SUCCESS, p_event_data->user_confirmation_request.bd_addr);
        /* get the remote name to show in the log */
        result = wiced_bt_dev_get_remote_name(p_event_data->user_confirmation_request.bd_addr, spp_bt_remote_name_callback);
        break;

    case BTM_PAIRING_IO_CAPABILITIES_BR_EDR_REQUEST_EVT:
        /* This application supports only Just Works pairing */
        WICED_BT_TRACE("BTM_PAIRING_IO_CAPABILITIES_REQUEST_EVT bda %B\n", p_event_data->pairing_io_capabilities_br_edr_request.bd_addr);
        p_event_data->pairing_io_capabilities_br_edr_request.local_io_cap   = BTM_IO_CAPABILITIES_NONE;
        p_event_data->pairing_io_capabilities_br_edr_request.auth_req       = BTM_AUTH_SINGLE_PROFILE_GENERAL_BONDING_NO;
        break;

    case BTM_PAIRING_COMPLETE_EVT:
        p_pairing_info = &p_event_data->pairing_complete.pairing_complete_info;
        WICED_BT_TRACE("Pairing Complete: %d\n", p_pairing_info->br_edr.status);
        result = WICED_BT_USE_DEFAULT_SECURITY;
        break;

    case BTM_ENCRYPTION_STATUS_EVT:
        p_encryption_status = &p_event_data->encryption_status;
        WICED_BT_TRACE("Encryption Status Event: bd (%B) res %d\n", p_encryption_status->bd_addr, p_encryption_status->result);
        break;

    case BTM_PAIRED_DEVICE_LINK_KEYS_UPDATE_EVT:
        /* This application supports a single paired host, we can save keys under the same NVRAM ID overwriting previous pairing if any */
        app_write_nvram(SPP_NVRAM_ID, sizeof(wiced_bt_device_link_keys_t), &p_event_data->paired_device_link_keys_update);
        break;

    case  BTM_PAIRED_DEVICE_LINK_KEYS_REQUEST_EVT:
        /* read existing key from the NVRAM  */
        if (app_read_nvram(SPP_NVRAM_ID, &p_event_data->paired_device_link_keys_request, sizeof(wiced_bt_device_link_keys_t)) != 0)
        {
            result = WICED_BT_SUCCESS;
        }
        else
        {
            result = WICED_BT_ERROR;
            WICED_BT_TRACE("Key retrieval failure\n");
        }
        break;

    case BTM_POWER_MANAGEMENT_STATUS_EVT:
        p_power_mgmt_notification = &p_event_data->power_mgmt_notification;
        WICED_BT_TRACE("Power mgmt status event: bd (%B) status:%d hci_status:%d\n", p_power_mgmt_notification->bd_addr, \
                p_power_mgmt_notification->status, p_power_mgmt_notification->hci_status);
        break;

    default:
        result = WICED_BT_USE_DEFAULT_SECURITY;
        break;
    }
    return result;
}


/*
 *  Prepare extended inquiry response data.  Current version publishes device name and 16bit
 *  SPP service.
 */
void app_write_eir(void)
{
    uint8_t *pBuf;
    uint8_t *p;
    uint8_t length;
    uint16_t eir_length;

    pBuf = (uint8_t *)wiced_bt_get_buffer(WICED_EIR_BUF_MAX_SIZE);
    WICED_BT_TRACE("hci_control_write_eir %x\n", pBuf);

    if (!pBuf)
    {
        WICED_BT_TRACE("app_write_eir %x\n", pBuf);
        return;
    }

    p = pBuf;

    length = strlen((char *)wiced_bt_cfg_settings.device_name);

    *p++ = length + 1;
    *p++ = BT_EIR_COMPLETE_LOCAL_NAME_TYPE;        // EIR type full name
    memcpy(p, wiced_bt_cfg_settings.device_name, length);
    p += length;

    *p++ = 2 + 1;                                   // Length of 16 bit services
    *p++ = BT_EIR_COMPLETE_16BITS_UUID_TYPE;        // 0x03 EIR type full list of 16 bit service UUIDs
    *p++ = UUID_SERVCLASS_SERIAL_PORT & 0xff;
    *p++ = (UUID_SERVCLASS_SERIAL_PORT >> 8) & 0xff;

    *p++ = 0;                                       // end of EIR Data is 0

    eir_length = (uint16_t) (p - pBuf);

    // print EIR data
    WICED_BT_TRACE_ARRAY(pBuf, MIN(p-pBuf, 100), "EIR :");
    wiced_bt_dev_write_eir(pBuf, eir_length);

    return;
}

/*
 * The function invoked on timeout of app seconds timer.
 */
#if SEND_DATA_ON_TIMEOUT
void app_timeout(TIMER_PARAM_TYPE arg)
{
    static uint32_t timer_count = 0;
    timer_count++;
    wiced_bool_t ret;
    WICED_BT_TRACE("app_timeout: %d, handle %d \n", timer_count, spp_handle);
    if (spp_handle != 0)
    {
        ret = wiced_bt_spp_send_session_data(spp_handle, (uint8_t *)&timer_count, sizeof(uint32_t));
        if (ret != WICED_TRUE)
            WICED_BT_TRACE("wiced_bt_spp_send_session_data failed, ret = %d\n", ret);
    }
}
#endif

/*
 * SPP connection up callback
 */
void spp_connection_up_callback(uint16_t handle, uint8_t* bda)
{
    WICED_BT_TRACE("%s handle:%d address:%B\n", __FUNCTION__, handle, bda);
    spp_handle = handle;
    spp_rx_bytes = 0;
}

/*
 * SPP connection down callback
 */
void spp_connection_down_callback(uint16_t handle)
{
    WICED_BT_TRACE("%s handle:%d rx_bytes:%d\n", __FUNCTION__, handle, spp_rx_bytes);
    spp_handle = 0;
#if defined(SEND_DATA_ON_INTERRUPT) && (SEND_DATA_ON_INTERRUPT==1)
    app_send_offset = 0;
    spp_tx_retry_count = 0;

    if(wiced_is_timer_in_use(&app_tx_timer))
    wiced_stop_timer(&app_tx_timer);
#endif
}

/*
 * Process data received over EA session.  Return TRUE if we were able to allocate buffer to
 * deliver to the host.
 */
wiced_bool_t spp_rx_data_callback(uint16_t handle, uint8_t* p_data, uint32_t data_len)
{
//    int i;
//    wiced_bt_buffer_statistics_t buffer_stats[4];

//    wiced_bt_get_buffer_usage (buffer_stats, sizeof(buffer_stats));

//    WICED_BT_TRACE("0:%d/%d 1:%d/%d 2:%d/%d 3:%d/%d\n", buffer_stats[0].current_allocated_count, buffer_stats[0].max_allocated_count,
//                   buffer_stats[1].current_allocated_count, buffer_stats[1].max_allocated_count,
//                   buffer_stats[2].current_allocated_count, buffer_stats[2].max_allocated_count,
//                   buffer_stats[3].current_allocated_count, buffer_stats[3].max_allocated_count);
//    buffer_report("spp_rx_data_callback");

//    wiced_result_t wiced_bt_get_buffer_usage (&buffer_stats, sizeof(buffer_stats));

    spp_rx_bytes += data_len;

    WICED_BT_TRACE("%s handle:%d len:%d %02x-%02x, total rx %d\n", __FUNCTION__, handle, data_len, p_data[0], p_data[data_len - 1], spp_rx_bytes);

#if LOOPBACK_DATA
    return wiced_bt_spp_send_session_data(handle, p_data, data_len);
#else
    return WICED_TRUE;
#endif
}

/*
 * spp_bt_remote_name_callback
 */
static void spp_bt_remote_name_callback(wiced_bt_dev_remote_name_result_t *p_remote_name_result)
{
    WICED_BT_TRACE("Pairing with: BdAddr:%B Status:%d Len:%d Name:%s\n",
            p_remote_name_result->bd_addr, p_remote_name_result->status,
            p_remote_name_result->length, p_remote_name_result->remote_bd_name);
}

/*
 * Write NVRAM function is called to store information in the NVRAM.
 */
int app_write_nvram(int nvram_id, int data_len, void *p_data)
{
    wiced_result_t  result;
    int             bytes_written = wiced_hal_write_nvram(nvram_id, data_len, (uint8_t*)p_data, &result);

    WICED_BT_TRACE("NVRAM ID:%d written :%d bytes result:%d\n", nvram_id, bytes_written, result);
    return (bytes_written);
}

/*
 * Read data from the NVRAM and return in the passed buffer
 */
int app_read_nvram(int nvram_id, void *p_data, int data_len)
{
    uint16_t        read_bytes = 0;
    wiced_result_t  result;

    if (data_len >= sizeof(wiced_bt_device_link_keys_t))
    {
        read_bytes = wiced_hal_read_nvram(nvram_id, sizeof(wiced_bt_device_link_keys_t), p_data, &result);
        WICED_BT_TRACE("NVRAM ID:%d read out of %d bytes:%d result:%d\n", nvram_id, sizeof(wiced_bt_device_link_keys_t), read_bytes, result);
    }
    return (read_bytes);
}

#if SEND_DATA_ON_INTERRUPT
/*
 * Test function which sends as much data as possible.
 */
void app_send_data(void)
{
    int i;
    wiced_bool_t ret;

    while ((spp_handle != 0) && (app_send_offset != APP_TOTAL_DATA_TO_SEND))
    {
        int bytes_to_send = app_send_offset + SPP_MAX_PAYLOAD < APP_TOTAL_DATA_TO_SEND ? SPP_MAX_PAYLOAD : APP_TOTAL_DATA_TO_SEND - app_send_offset;
        ret = wiced_bt_spp_can_send_more_data(spp_handle);
        if(!ret)
        {
            // buffer_report(" app_send_data can't send");
            // WICED_BT_TRACE(" ! return from wiced_bt_spp_can_send_more_data\n");
            break;
        }
        for (i = 0; i < bytes_to_send; i++)
        {
            app_send_buffer[i] = app_send_offset + i;
        }
        ret = wiced_bt_spp_send_session_data(spp_handle, app_send_buffer, bytes_to_send);
        if(ret != WICED_TRUE)
        {
            // WICED_BT_TRACE(" ! return from wiced_bt_spp_send_session_data\n");
            break;
        }
        app_send_offset += bytes_to_send;
        spp_tx_retry_count = 0;
    }
    // Check if we were able to send everything
    if (app_send_offset < APP_TOTAL_DATA_TO_SEND)
    {
        if(spp_tx_retry_count >= MAX_TX_RETRY)
        {
		WICED_BT_TRACE("Reached max tx retries! Terminating transfer!\n");
		WICED_BT_TRACE("Make sure peer device is providing us credits\n");
		app_send_offset = 0;
        }
        else
        {
            WICED_BT_TRACE("wiced_start_timer app_tx_timer %d\n", app_send_offset);
		wiced_start_timer(&app_tx_timer, TX_RETRY_TIMEOUT);
		spp_tx_retry_count++;
        }
    }
    else
    {
        uint32_t time_tx = clock_SystemTimeMicroseconds64() / 1000 - time_start;
        WICED_BT_TRACE("sent %d in %dmsec (%dKbps)\n", APP_TOTAL_DATA_TO_SEND, time_tx, APP_TOTAL_DATA_TO_SEND * 8 / time_tx);
        app_send_offset = 0;
    }
}

/*
 * Test function which start sending data.
 */
void app_interrupt_handler(void *data, uint8_t port_pin)
{
    WICED_BT_TRACE("gpio_interrupt_handler pin:%d send_offset:%d\n", port_pin, app_send_offset);
    time_start = clock_SystemTimeMicroseconds64() / 1000;

     /* Get the status of interrupt on P# */
    if (wiced_hal_gpio_get_pin_interrupt_status(BUTTON_GPIO))
    {
        /* Clear the GPIO interrupt */
        wiced_hal_gpio_clear_pin_interrupt_status(BUTTON_GPIO);
    }
    // If we are already sending data, do nothing
    if (app_send_offset != 0)
        return;

    app_send_data();
}

/*
 * The timeout function is periodically called while we are sending big amount of data
 */
void app_tx_ack_timeout(TIMER_PARAM_TYPE param)
{
    app_send_data();
}
#endif


#ifdef HCI_TRACE_OVER_TRANSPORT
/*
 *  Pass protocol traces up over the transport
 */
void app_trace_callback(wiced_bt_hci_trace_type_t type, uint16_t length, uint8_t* p_data)
{
#if BTSTACK_VER >= 0x03000001
    wiced_transport_send_hci_trace( type, p_data, length );
#else
    wiced_transport_send_hci_trace(host_trans_pool, type, length, p_data);
#endif
}
#endif

 

우선은 debug print를 UART로 보고 싶으니 debug를 PUART로 바꿔 놓는다.

    APPLICATION_START()
    {
    ...
        //wiced_set_debug_uart(WICED_ROUTE_DEBUG_TO_WICED_UART);
        wiced_hal_puart_configuration(921600, PARITY_NONE, STOP_BIT_1);
        wiced_set_debug_uart(WICED_ROUTE_DEBUG_TO_PUART);
    ...
    }

 

spp를 연결하면 button push를 인식하여 Tx throughput을 측정하는 것은 지원한다.

app_management_callback 2
Power mgmt status event: bd (be ef be ef 7e f6 ) status:2 hci_status:0
wiced_start_timer app_tx_timer 961685
wiced_start_timer app_tx_timer 961685
wiced_start_timer app_tx_timer 961685
wiced_start_timer app_tx_timer 961685
app_management_callback 2
Power mgmt status event: bd (be ef be ef 7e f6 ) status:0 hci_status:0
wiced_start_timer app_tx_timer 961685
wiced_start_timer app_tx_timer 964706
wiced_start_timer app_tx_timer 970748
wiced_start_timer app_tx_timer 976790
wiced_start_timer app_tx_timer 982832
wiced_start_timer app_tx_timer 988874
wiced_start_timer app_tx_timer 994916
sent 1000000 in 23744msec (336Kbps)
app_management_callback 2
Power mgmt status event: bd (be ef be ef 7e f6 ) status:2 hci_status:0

1M 보내는데 23초가 걸린다. 이건 사용할 수 없는 수준이다. 

 

반복되는 Power mgmt status event가 수상하다.

p_power_mgmt_notification->status가 0 -> 2 -> 0 으로 계속 변경되는데 확인해보면 0은 active mode, 2는 sniff mode로 들어갔다는 이야기다.

sniff상태로 data를 보내면 상당히 느리기 때문에 우선 sniff에 들어가지 않도록 해야 한다.

 

API document를 살펴보자.

https://infineon.github.io/btsdk-docs/BT-SDK/20719-B2_Bluetooth/API/index.html

 

AIROC™ CYW20719: Main Page

This page collects software and hardware documentation related to the CYW20719 family of devices and evaluation kits. Links to AIROC™ BTSDK software API reference material, user guides, and hardware documentation can be found below. AIROC™ API Referenc

infineon.github.io

wiced_bt_dev_cancel_sniff_mode()를 지원한다. 그런데 이건 sniff에서 빠져나오는 것이다. 우리가 필요한 것은 sniff에 들어가지 않는 것인다.

wiced_bt_dev_set_link_policy()는 연결되어 있는 device마다 link와 관련된 setting을 정할 수 있다.

API가 모두 wiced로 시작하는 것은 AIROC이 이전에는 WICED라는 이름으로 출발했기 때문이다.

parameter로 bd address와 link settings가 필요하다. bd address는 연결할 때 저장했다가 사용하면 되고, settings는 hcidefs.h를 참고하면 된다.

/* Policy settings status */
#define HCI_DISABLE_ALL_LM_MODES        0x0000
#define HCI_ENABLE_ROLE_SWITCH          0x0001
#define HCI_ENABLE_HOLD_MODE            0x0002
#define HCI_ENABLE_SNIFF_MODE           0x0004
#define HCI_ENABLE_PARK_MODE            0x0008
/*
 * SPP connection up callback
 */
 wiced_bt_device_address_t       peer_addr;
void spp_connection_up_callback(uint16_t handle, uint8_t* bda)
{
	uint16_t link_settings;
    WICED_BT_TRACE("%s handle:%d address:%B\n", __FUNCTION__, handle, bda);
    spp_handle = handle;
    spp_rx_bytes = 0;
    memcpy(peer_addr, bda, 6);
    link_settings = HCI_ENABLE_ROLE_SWITCH;
    wiced_bt_dev_set_link_policy(peer_addr, &link_settings);
}

연결하고나면 link policy를 변경하여 sniff에 빠지 않게 한다.

크게 필요해 보이진 않지만 app_send_data()에도 wiced_bt_dev_cancel_sniff_mode(peer_addr);를 추가하여 혹시라도 sniff에 들어갔다가면 나올 수 있게 해준다.

wiced_start_timer app_tx_timer 958664
wiced_start_timer app_tx_timer 964706
wiced_start_timer app_tx_timer 970748
wiced_start_timer app_tx_timer 976790
wiced_start_timer app_tx_timer 982832
wiced_start_timer app_tx_timer 988874
wiced_start_timer app_tx_timer 994916
sent 1000000 in 17277msec (463Kbps)

대략 17초로 줄어들긴 했지만 이걸로 만족할 수는 없다.

 

code를 보면 app_tx_timer를 TX_RETRY_TIMEOUT 주기로 호출하여 app_tx_ack_timeout callback을 부른다.

app_tx_ack_timeout에서 app_send_data();를 이용하여 Tx를 하고 있다.

즉, 100ms마다 data를 보내게 된다.

#define MAX_TX_RETRY                 100
#define TX_RETRY_TIMEOUT             10 // msec
wiced_start_timer app_tx_timer 982832
wiced_start_timer app_tx_timer 982832
wiced_start_timer app_tx_timer 985853
wiced_start_timer app_tx_timer 988874
wiced_start_timer app_tx_timer 991895
wiced_start_timer app_tx_timer 994916
wiced_start_timer app_tx_timer 997937
sent 1000000 in 4602msec (1738Kbps)

약 5초가량이 되었다.

 

수정된 spp.c code (더보기를 누르면 전체 코드를 확인 가능)

더보기
/*
 * Copyright 2016-2022, Cypress Semiconductor Corporation (an Infineon company) or
 * an affiliate of Cypress Semiconductor Corporation.  All rights reserved.
 *
 * This software, including source code, documentation and related
 * materials ("Software") is owned by Cypress Semiconductor Corporation
 * or one of its affiliates ("Cypress") and is protected by and subject to
 * worldwide patent protection (United States and foreign),
 * United States copyright laws and international treaty provisions.
 * Therefore, you may use this Software only as provided in the license
 * agreement accompanying the software package from which you
 * obtained this Software ("EULA").
 * If no EULA applies, Cypress hereby grants you a personal, non-exclusive,
 * non-transferable license to copy, modify, and compile the Software
 * source code solely for use in connection with Cypress's
 * integrated circuit products.  Any reproduction, modification, translation,
 * compilation, or representation of this Software except as specified
 * above is prohibited without the express written permission of Cypress.
 *
 * Disclaimer: THIS SOFTWARE IS PROVIDED AS-IS, WITH NO WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, NONINFRINGEMENT, IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Cypress
 * reserves the right to make changes to the Software without notice. Cypress
 * does not assume any liability arising out of the application or use of the
 * Software or any product or circuit described in the Software. Cypress does
 * not authorize its products for use in any products where a malfunction or
 * failure of the Cypress product may reasonably be expected to result in
 * significant property damage, injury or death ("High Risk Product"). By
 * including Cypress's product in a High Risk Product, the manufacturer
 * of such system or application assumes all risk of such use and in doing
 * so agrees to indemnify Cypress against all liability.
 */

/** @file
 *
 * SPP Application for 20XXX devices.
 *
 * SPP application uses SPP profile library to establish, terminate, send and receive SPP
 * data over BR/EDR. This sample supports single a single SPP connection.
 *
 * Following compilation flags are important for testing
 *  HCI_TRACE_OVER_TRANSPORT - configures HCI traces to be routed to the WICED HCI interface
 *  WICED_BT_TRACE_ENABLE    - enables WICED_BT_TRACEs.  You can also modify makefile.mk to build
 *                             with _debug version of the library
 *  SEND_DATA_ON_INTERRUPT   - if defined, the app will send 1Meg of data on application button push
 *  SEND_DATA_ON_TIMEOUT     - if defined, the app will send 4 bytes every second while session is up
 *  LOOPBACK_DATA            - if enabled, the app sends back received data
 *
 * To demonstrate the app, work through the following steps.
 * 1. Build and download the application to the WICED board.
 * 2. Open the Bluetooth Classic and LE Profile Client Control application and open the port for WICED HCI for the device.
 *    Default baud rate configured in the application is defined by the BSP HCI_UART_DEAULT_BAUD #define,
 *    usually either 3M or 115200 depending on board UART capabilities.
 * 3. Run the BTSpy program to view protocol and application traces.
 *    See "Bluetooth Classic and LE Profile Client Control" and "BTSpy" in chip-specifc readme.txt for more information about these apps.
 * 4. On Windows 10 PCs, right click on the Bluetooth icon in the system tray and
 *    select 'Add a Bluetooth Device'. Find and pair with the spp app. That should create an incoming and an outgoing
 *    COM port on your computer. Right click on the Bluetooth icon in the system tray and
 *    select 'Open Settings', scroll down and select "More Bluetooth options" and then
 *    select the 'COM Ports' tab.
 * 5. Use application such as Term Term to open the outgoing COM port. Opening the port
 *    will create the SPP connection.
 * 6. Type any key on the terminal of the outgoing COM port, the spp application will receive the key.
 * 7. By default, (SEND_DATA_ON_INTERRUPT=1) the application sends 1 MB data to the peer application on every
 *    App button press on the WICED board.
 * 8. If desired, edit the spp.c file to configure the application to send data on a timer to the peer application by
 *    setting SEND_DATA_ON_INTERRUPT=0 and SEND_DATA_ON_TIMEOUT=1*
 *
 * Features demonstrated
 *  - Use of SPP library
 *
 *  Note: This snippet app does not support WICED HCI Control and may use transport only for tracing.
 *  If you route traces to WICED HCI UART, use ClientControl app with baud rate equal to that
 *  set in the wiced_transport_cfg_t structure below (currently set at HCI_UART_DEFAULT_BAUD, either 3 Mbps or 115200
 *  depending on the capabilities of the board used).
 */

#include "sparcommon.h"
#include "bt_types.h"
#include "wiced.h"
#include "wiced_gki.h"
#include "wiced_bt_dev.h"
#include "wiced_bt_sdp.h"
#include "wiced_bt_ble.h"
#include "wiced_bt_uuid.h"
#include "wiced_hal_nvram.h"
#include "wiced_bt_trace.h"
#include "wiced_bt_cfg.h"
#include "wiced_bt_spp.h"
#include "wiced_hci.h"
#include "wiced_timer.h"
#include "wiced_transport.h"
#include "wiced_platform.h"
#include "wiced_memory.h"
#include "string.h"
#include "wiced_bt_stack.h"
#include "wiced_bt_rfcomm.h"
#include "cycfg_sdp_db.h"
#include "wiced_hal_puart.h"
#if defined(CYW20706A2) || defined(CYW43012C0)
#include "wiced_bt_app_hal_common.h"
#endif

#if BTSTACK_VER >= 0x03000001
#include "wiced_memory.h"
#include "clock_timer.h"
#define BT_STACK_HEAP_SIZE          1024 * 6
wiced_bt_heap_t *p_default_heap   = NULL;
#endif

#define HCI_TRACE_OVER_TRANSPORT            1   // If defined HCI traces are send over transport/WICED HCI interface
// configure either SEND_DATA_ON_INTERRUPT or SEND_DATA_ON_TIMEOUT, but not both
// CYW9M2BASE-43012BT does not support SEND_DATA_ON_INTERRUPT because the platform does not have button connected to Bluetooth board.
#if defined (NO_BUTTON_SUPPORT)
#if defined(SEND_DATA_ON_INTERRUPT) && (SEND_DATA_ON_INTERRUPT==1)
#undef SEND_DATA_ON_INTERRUPT                   // disable SEND_DATA_ON_INTERRUPT is no app button
#define SEND_DATA_ON_TIMEOUT                1
#endif
#endif

//#define LOOPBACK_DATA                     1   // If defined application loops back received data

#define WICED_EIR_BUF_MAX_SIZE              264
#define SPP_NVRAM_ID                        WICED_NVRAM_VSID_START

/* Max TX packet to be sent over SPP */
#define MAX_TX_BUFFER                       1017
#define TRANS_MAX_BUFFERS                   2
#define TRANS_UART_BUFFER_SIZE              1024
#define SPP_MAX_PAYLOAD                     1007

#if SEND_DATA_ON_INTERRUPT
#include "wiced_hal_gpio.h"
#include "wiced_platform.h"

#define APP_TOTAL_DATA_TO_SEND             1000000
#define BUTTON_GPIO                         WICED_P30

#if defined(CYW43012C0)
#define WICED_PLATFORM_BUTTON_1          WICED_P00
#ifndef WICED_GPIO_BUTTON
#define WICED_GPIO_BUTTON                WICED_PLATFORM_BUTTON_1
#endif
#ifndef WICED_GPIO_BUTTON_DEFAULT_STATE
#define WICED_GPIO_BUTTON_DEFAULT_STATE  GPIO_PIN_OUTPUT_HIGH
#endif
#endif

int     app_send_offset = 0;
uint8_t app_send_buffer[SPP_MAX_PAYLOAD];
uint32_t time_start = 0;
#endif

#ifdef SEND_DATA_ON_TIMEOUT
wiced_timer_t spp_app_timer;
void app_timeout(TIMER_PARAM_TYPE arg);
#endif

/*****************************************************************************
**  Structures
*****************************************************************************/
#define SPP_RFCOMM_SCN               2

#define MAX_TX_RETRY                 100
#define TX_RETRY_TIMEOUT             10 // msec

static void         spp_connection_up_callback(uint16_t handle, uint8_t* bda);
static void         spp_connection_down_callback(uint16_t handle);
static wiced_bool_t spp_rx_data_callback(uint16_t handle, uint8_t* p_data, uint32_t data_len);
static void         spp_bt_remote_name_callback(wiced_bt_dev_remote_name_result_t *p_remote_name_result);

wiced_bt_spp_reg_t spp_reg =
{
    SPP_RFCOMM_SCN,                     /* RFCOMM service channel number for SPP connection */
    MAX_TX_BUFFER,                      /* RFCOMM MTU for SPP connection */
    spp_connection_up_callback,         /* SPP connection established */
    NULL,                               /* SPP connection establishment failed, not used because this app never initiates connection */
    NULL,                               /* SPP service not found, not used because this app never initiates connection */
    spp_connection_down_callback,       /* SPP connection disconnected */
    spp_rx_data_callback,               /* Data packet received */
};
#if BTSTACK_VER < 0x03000001
wiced_transport_buffer_pool_t*  host_trans_pool;
#endif
uint16_t                        spp_handle = 0;
wiced_timer_t                   app_tx_timer;
uint32_t                        spp_rx_bytes = 0;
uint32_t                        spp_tx_retry_count = 0;
wiced_bt_device_address_t       peer_addr;
uint8_t pincode[4] = { 0x30, 0x30, 0x30, 0x30 };

extern const wiced_bt_cfg_settings_t wiced_bt_cfg_settings;
#if BTSTACK_VER < 0x03000001
extern const wiced_bt_cfg_buf_pool_t wiced_bt_cfg_buf_pools[WICED_BT_CFG_NUM_BUF_POOLS];
#endif

#if defined WICED_BT_TRACE_ENABLE || defined HCI_TRACE_OVER_TRANSPORT
const wiced_transport_cfg_t transport_cfg =
{
    .type = WICED_TRANSPORT_UART,
    .cfg =
    {
        .uart_cfg =
        {
            .mode = WICED_TRANSPORT_UART_HCI_MODE,
            .baud_rate =  HCI_UART_DEFAULT_BAUD
        },
    },
#if BTSTACK_VER >= 0x03000001
        .heap_config =
        {
            .data_heap_size = 1024 * 4 + 1500 * 2,
            .hci_trace_heap_size = 1024 * 2,
            .debug_trace_heap_size = 1024,
        },
#else
    .rx_buff_pool_cfg =
    {
        .buffer_size  = TRANS_UART_BUFFER_SIZE,
        .buffer_count = 1
    },
#endif
    .p_status_handler    = NULL,
    .p_data_handler      = NULL,
    .p_tx_complete_cback = NULL
};
#endif

/*******************************************************************
 * Function Prototypes
 ******************************************************************/
static wiced_bt_dev_status_t app_management_callback (wiced_bt_management_evt_t event, wiced_bt_management_evt_data_t *p_event_data);
static void                  app_write_eir(void);
static int                   app_write_nvram(int nvram_id, int data_len, void *p_data);
static int                   app_read_nvram(int nvram_id, void *p_data, int data_len);

#if SEND_DATA_ON_INTERRUPT
static void                  app_tx_ack_timeout(TIMER_PARAM_TYPE param);
static void                  app_interrupt_handler(void *data, uint8_t port_pin);
#endif
#ifdef HCI_TRACE_OVER_TRANSPORT
static void                  app_trace_callback(wiced_bt_hci_trace_type_t type, uint16_t length, uint8_t* p_data);
#endif

#if defined (CYW20706A2)
extern BOOL32 wiced_hal_puart_select_uart_pads(UINT8 rxdPin, UINT8 txdPin, UINT8 ctsPin, UINT8 rtsPin);
extern wiced_result_t wiced_bt_app_init( void );
#endif

#ifndef CYW20706A2
extern uint64_t clock_SystemTimeMicroseconds64();
#else
#include "rtc.h"
uint64_t clock_SystemTimeMicroseconds64(void)
{
    tRTC_REAL_TIME_CLOCK rtcClock;
    rtc_getRTCRawClock(&rtcClock);
    // To convert 128 kHz rtc timer to milliseconds divide it by 131: //128 kHz = 128 * 1024 = 131072; to microseconds: 1000000 / 131072 = 7.62939453125 (7.63)
    return rtcClock.rtc64 * 763 / 100;
}
#endif

/*******************************************************************
 * Function Definitions
 ******************************************************************/

void buffer_report(char *msg)
{
#if BTSTACK_VER >= 0x03000001
    /*
     * Get statistics of default heap.
     * TODO: get statistics of stack heap (btu_cb.p_heap)
     */
    wiced_bt_heap_statistics_t heap_stat;

    if (wiced_bt_get_heap_statistics(p_default_heap, &heap_stat))
    {
        WICED_BT_TRACE("--- heap_size:%d ---\n", heap_stat.heap_size);
        WICED_BT_TRACE("max_single_allocation:%d max_heap_size_used:%d\n",
                        heap_stat.max_single_allocation,
                        heap_stat.max_heap_size_used);
        WICED_BT_TRACE("allocation_failure_count:%d current_largest_free_size:%d\n",
                        heap_stat.allocation_failure_count,
                        heap_stat.current_largest_free_size);
        WICED_BT_TRACE("current_num_allocations:%d current_size_allocated:%d\n",
                        heap_stat.current_num_allocations,
                        heap_stat.current_size_allocated);
        WICED_BT_TRACE("current_num_free_fragments:%d current_free_size\n",
                        heap_stat.current_num_free_fragments,
                        heap_stat.current_free_size);
    }
    else
    {
        WICED_BT_TRACE("buffer_report: wiced_bt_get_heap_statistics failed\n");
    }
#else /* !BTSTACK_VER */

    wiced_bt_buffer_statistics_t buffer_stats[5];
    wiced_result_t result;

    result = wiced_bt_get_buffer_usage (buffer_stats, sizeof(buffer_stats));

    if (result == WICED_BT_SUCCESS)
    {
        WICED_BT_TRACE("%s: pool %x %d %d/%d/%d\n", msg,
                buffer_stats[1].pool_id,
                buffer_stats[1].pool_size,
                buffer_stats[1].current_allocated_count,
                buffer_stats[1].max_allocated_count,
                buffer_stats[1].total_count);
        WICED_BT_TRACE("%s: pool %x %d %d/%d/%d\n", msg,
                buffer_stats[2].pool_id,
                buffer_stats[2].pool_size,
                buffer_stats[2].current_allocated_count,
                buffer_stats[2].max_allocated_count,
                buffer_stats[2].total_count);
    }
    else
        WICED_BT_TRACE("buffer_report: wiced_bt_get_buffer_usage failed, returned %d\n", result);
#endif
}

/*
 * Entry point to the application. Set device configuration and start Bluetooth
 * stack initialization.  The actual application initialization will happen
 * when stack reports that Bluetooth device is ready
 */
APPLICATION_START()
{
    wiced_result_t result;
    int interupt = 0, timeout = 0, loopback = 0;

#if defined WICED_BT_TRACE_ENABLE || defined HCI_TRACE_OVER_TRANSPORT
    wiced_transport_init(&transport_cfg);

#if BTSTACK_VER < 0x03000001
    // create special pool for sending data to the MCU
    host_trans_pool = wiced_transport_create_buffer_pool(TRANS_UART_BUFFER_SIZE, TRANS_MAX_BUFFERS);
#endif

    // Set the debug uart as WICED_ROUTE_DEBUG_NONE to get rid of prints
    // wiced_set_debug_uart(WICED_ROUTE_DEBUG_NONE);

    // Set to PUART to see traces on peripheral uart(puart) if platform has PUART
#ifdef NO_PUART_SUPPORT
    // wiced_set_debug_uart( WICED_ROUTE_DEBUG_TO_WICED_UART );
#else
    // wiced_set_debug_uart( WICED_ROUTE_DEBUG_TO_PUART );
#if defined (CYW20706A2)
    // wiced_hal_puart_select_uart_pads( WICED_PUART_RXD, WICED_PUART_TXD, 0, 0);
#endif
#endif

    // Set to HCI to see traces on HCI uart - default if no call to wiced_set_debug_uart()
    // wiced_set_debug_uart( WICED_ROUTE_DEBUG_TO_HCI_UART );

    // Use WICED_ROUTE_DEBUG_TO_WICED_UART to send formatted debug strings over the WICED
    // HCI debug interface to be parsed by ClientControl/BtSpy.
    //wiced_set_debug_uart(WICED_ROUTE_DEBUG_TO_WICED_UART);
    wiced_hal_puart_configuration(921600, PARITY_NONE, STOP_BIT_1);
    wiced_set_debug_uart(WICED_ROUTE_DEBUG_TO_PUART);
#endif

#if SEND_DATA_ON_INTERRUPT
    interupt = 1;
#endif
#if SEND_DATA_ON_TIMEOUT
    timeout = 1;
#endif
#if LOOPBACK_DATA
    loopback = 1;
#endif
    WICED_BT_TRACE("APP Start, interupt=%d, timeout=%d, loopback=%d\n", interupt, timeout, loopback);

#if BTSTACK_VER >= 0x03000001
    /* Create default heap */
    p_default_heap = wiced_bt_create_heap("default_heap", NULL, BT_STACK_HEAP_SIZE, NULL, WICED_TRUE);
    if (p_default_heap == NULL)
    {
        WICED_BT_TRACE("create default heap error: size %d\n", BT_STACK_HEAP_SIZE);
        return;
    }
    /* Initialize Stack and Register Management Callback */
    // Register call back and configuration with stack
    wiced_bt_stack_init(app_management_callback, &wiced_bt_cfg_settings);
#else
    /* Initialize Stack and Register Management Callback */
    // Register call back and configuration with stack
    wiced_bt_stack_init(app_management_callback, &wiced_bt_cfg_settings, wiced_bt_cfg_buf_pools);
#endif
}

/*
 * SPP application initialization is executed after Bluetooth stack initialization is completed.
 */
void application_init(void)
{
    wiced_result_t         result;

#if defined (CYW20706A2)
    /* Initialize wiced app */
    wiced_bt_app_init();

    /* Initialize the RTC block */
    rtc_init();
#endif

#if SEND_DATA_ON_INTERRUPT
#if !defined (CYW20706A2) && !defined (CYW43012C0)
    /* Configure the button available on the platform */
    wiced_platform_register_button_callback( WICED_PLATFORM_BUTTON_1, app_interrupt_handler, NULL, WICED_PLATFORM_BUTTON_RISING_EDGE);
#elif defined(CYW20706A2) || defined(CYW43012C0)
/* Initializes the GPIO driver */
    wiced_bt_app_hal_init();
	wiced_hal_gpio_configure_pin(WICED_GPIO_BUTTON, WICED_GPIO_BUTTON_SETTINGS( GPIO_EN_INT_RISING_EDGE ), WICED_GPIO_BUTTON_DEFAULT_STATE );
	wiced_hal_gpio_register_pin_for_interrupt(WICED_GPIO_BUTTON, app_interrupt_handler, NULL);
#endif // CYW20706A2 && CYW43012C0
    // init timer that we will use for the rx data flow control.
    wiced_init_timer(&app_tx_timer, app_tx_ack_timeout, 0, WICED_MILLI_SECONDS_TIMER);
#endif // SEND_DATA_ON_INTERRUPT

    app_write_eir();

#if defined (CYW20706A2)
    // Initialize RFCOMM.  We will not be using application buffer pool and will rely on the
    // stack pools configured in the wiced_bt_cfg.c
    wiced_bt_rfcomm_init(MAX_TX_BUFFER, 1);
#endif

    // Initialize SPP library
    wiced_bt_spp_startup(&spp_reg);

#ifdef HCI_TRACE_OVER_TRANSPORT
    // There is a virtual HCI interface between upper layers of the stack and
    // the controller portion of the chip with lower layers of the Bluetooth stack.
    // Register with the stack to receive all HCI commands, events and data.
    wiced_bt_dev_register_hci_trace(app_trace_callback);
#endif
    /* create SDP records */
    wiced_bt_sdp_db_init((uint8_t *)sdp_database, sdp_database_len);

    /* Allow peer to pair */
    wiced_bt_set_pairable_mode(WICED_TRUE, 0);

#if BTSTACK_VER >= 0x03000001
        // This application will always configure device connectable and discoverable
    wiced_bt_dev_set_discoverability(BTM_GENERAL_DISCOVERABLE,
                                     WICED_BT_CFG_DEFAULT_INQUIRY_SCAN_INTERVAL,
                                     WICED_BT_CFG_DEFAULT_INQUIRY_SCAN_WINDOW);

    wiced_bt_dev_set_connectability(BTM_CONNECTABLE,
                                    WICED_BT_CFG_DEFAULT_PAGE_SCAN_INTERVAL,
                                    WICED_BT_CFG_DEFAULT_PAGE_SCAN_WINDOW);
#else
    // This application will always configure device connectable and discoverable
    wiced_bt_dev_set_discoverability(BTM_GENERAL_DISCOVERABLE,
        wiced_bt_cfg_settings.br_edr_scan_cfg.inquiry_scan_interval,
        wiced_bt_cfg_settings.br_edr_scan_cfg.inquiry_scan_window);

    wiced_bt_dev_set_connectability(BTM_CONNECTABLE,
        wiced_bt_cfg_settings.br_edr_scan_cfg.page_scan_interval,
        wiced_bt_cfg_settings.br_edr_scan_cfg.page_scan_window);
#endif

#if SEND_DATA_ON_TIMEOUT
    /* Starting the app timers, seconds timer and the ms timer  */
    wiced_init_timer(&spp_app_timer, app_timeout, 0, WICED_SECONDS_PERIODIC_TIMER);
    wiced_start_timer(&spp_app_timer, 1);
#endif
}

/*
 *  Management callback receives various notifications from the stack
 */
wiced_result_t app_management_callback(wiced_bt_management_evt_t event, wiced_bt_management_evt_data_t *p_event_data)
{
    wiced_result_t                      result = WICED_BT_SUCCESS;
    wiced_bt_dev_status_t               dev_status;
    wiced_bt_dev_pairing_info_t*        p_pairing_info;
    wiced_bt_dev_encryption_status_t*   p_encryption_status;
    int                                 bytes_written, bytes_read;
    wiced_bt_power_mgmt_notification_t* p_power_mgmt_notification;

    WICED_BT_TRACE("app_management_callback %d\n", event);

    switch(event)
    {
    /* Bluetooth  stack enabled */
    case BTM_ENABLED_EVT:
        application_init();
        //WICED_BT_TRACE("Free mem:%d", cfa_mm_MemFreeBytes());
        break;

    case BTM_DISABLED_EVT:
        break;

    case BTM_PIN_REQUEST_EVT:
        WICED_BT_TRACE("remote address= %B\n", p_event_data->pin_request.bd_addr);
        wiced_bt_dev_pin_code_reply(*p_event_data->pin_request.bd_addr,result/*WICED_BT_SUCCESS*/,4, &pincode[0]);
        break;

    case BTM_USER_CONFIRMATION_REQUEST_EVT:
        /* This application always confirms peer's attempt to pair */
        wiced_bt_dev_confirm_req_reply (WICED_BT_SUCCESS, p_event_data->user_confirmation_request.bd_addr);
        /* get the remote name to show in the log */
        result = wiced_bt_dev_get_remote_name(p_event_data->user_confirmation_request.bd_addr, spp_bt_remote_name_callback);
        break;

    case BTM_PAIRING_IO_CAPABILITIES_BR_EDR_REQUEST_EVT:
        /* This application supports only Just Works pairing */
        WICED_BT_TRACE("BTM_PAIRING_IO_CAPABILITIES_REQUEST_EVT bda %B\n", p_event_data->pairing_io_capabilities_br_edr_request.bd_addr);
        p_event_data->pairing_io_capabilities_br_edr_request.local_io_cap   = BTM_IO_CAPABILITIES_NONE;
        p_event_data->pairing_io_capabilities_br_edr_request.auth_req       = BTM_AUTH_SINGLE_PROFILE_GENERAL_BONDING_NO;
        break;

    case BTM_PAIRING_COMPLETE_EVT:
        p_pairing_info = &p_event_data->pairing_complete.pairing_complete_info;
        WICED_BT_TRACE("Pairing Complete: %d\n", p_pairing_info->br_edr.status);
        result = WICED_BT_USE_DEFAULT_SECURITY;
        break;

    case BTM_ENCRYPTION_STATUS_EVT:
        p_encryption_status = &p_event_data->encryption_status;
        WICED_BT_TRACE("Encryption Status Event: bd (%B) res %d\n", p_encryption_status->bd_addr, p_encryption_status->result);
        break;

    case BTM_PAIRED_DEVICE_LINK_KEYS_UPDATE_EVT:
        /* This application supports a single paired host, we can save keys under the same NVRAM ID overwriting previous pairing if any */
        app_write_nvram(SPP_NVRAM_ID, sizeof(wiced_bt_device_link_keys_t), &p_event_data->paired_device_link_keys_update);
        break;

    case  BTM_PAIRED_DEVICE_LINK_KEYS_REQUEST_EVT:
        /* read existing key from the NVRAM  */
        if (app_read_nvram(SPP_NVRAM_ID, &p_event_data->paired_device_link_keys_request, sizeof(wiced_bt_device_link_keys_t)) != 0)
        {
            result = WICED_BT_SUCCESS;
        }
        else
        {
            result = WICED_BT_ERROR;
            WICED_BT_TRACE("Key retrieval failure\n");
        }
        break;

    case BTM_POWER_MANAGEMENT_STATUS_EVT:
        p_power_mgmt_notification = &p_event_data->power_mgmt_notification;
        WICED_BT_TRACE("Power mgmt status event: bd (%B) status:%d hci_status:%d\n", p_power_mgmt_notification->bd_addr, \
                p_power_mgmt_notification->status, p_power_mgmt_notification->hci_status);
        break;

    default:
        result = WICED_BT_USE_DEFAULT_SECURITY;
        break;
    }
    return result;
}


/*
 *  Prepare extended inquiry response data.  Current version publishes device name and 16bit
 *  SPP service.
 */
void app_write_eir(void)
{
    uint8_t *pBuf;
    uint8_t *p;
    uint8_t length;
    uint16_t eir_length;

    pBuf = (uint8_t *)wiced_bt_get_buffer(WICED_EIR_BUF_MAX_SIZE);
    WICED_BT_TRACE("hci_control_write_eir %x\n", pBuf);

    if (!pBuf)
    {
        WICED_BT_TRACE("app_write_eir %x\n", pBuf);
        return;
    }

    p = pBuf;

    length = strlen((char *)wiced_bt_cfg_settings.device_name);

    *p++ = length + 1;
    *p++ = BT_EIR_COMPLETE_LOCAL_NAME_TYPE;        // EIR type full name
    memcpy(p, wiced_bt_cfg_settings.device_name, length);
    p += length;

    *p++ = 2 + 1;                                   // Length of 16 bit services
    *p++ = BT_EIR_COMPLETE_16BITS_UUID_TYPE;        // 0x03 EIR type full list of 16 bit service UUIDs
    *p++ = UUID_SERVCLASS_SERIAL_PORT & 0xff;
    *p++ = (UUID_SERVCLASS_SERIAL_PORT >> 8) & 0xff;

    *p++ = 0;                                       // end of EIR Data is 0

    eir_length = (uint16_t) (p - pBuf);

    // print EIR data
    WICED_BT_TRACE_ARRAY(pBuf, MIN(p-pBuf, 100), "EIR :");
    wiced_bt_dev_write_eir(pBuf, eir_length);

    return;
}

/*
 * The function invoked on timeout of app seconds timer.
 */
#if SEND_DATA_ON_TIMEOUT
void app_timeout(TIMER_PARAM_TYPE arg)
{
    static uint32_t timer_count = 0;
    timer_count++;
    wiced_bool_t ret;
    WICED_BT_TRACE("app_timeout: %d, handle %d \n", timer_count, spp_handle);
    if (spp_handle != 0)
    {
        ret = wiced_bt_spp_send_session_data(spp_handle, (uint8_t *)&timer_count, sizeof(uint32_t));
        if (ret != WICED_TRUE)
            WICED_BT_TRACE("wiced_bt_spp_send_session_data failed, ret = %d\n", ret);
    }
}
#endif

/*
 * SPP connection up callback
 */
void spp_connection_up_callback(uint16_t handle, uint8_t* bda)
{
	uint16_t link_settings;
    WICED_BT_TRACE("%s handle:%d address:%B\n", __FUNCTION__, handle, bda);
    spp_handle = handle;
    spp_rx_bytes = 0;
    memcpy(peer_addr, bda, 6);
    link_settings = HCI_ENABLE_ROLE_SWITCH;
    wiced_bt_dev_set_link_policy(peer_addr, &link_settings);
}

/*
 * SPP connection down callback
 */
void spp_connection_down_callback(uint16_t handle)
{
    WICED_BT_TRACE("%s handle:%d rx_bytes:%d\n", __FUNCTION__, handle, spp_rx_bytes);
    spp_handle = 0;
#if defined(SEND_DATA_ON_INTERRUPT) && (SEND_DATA_ON_INTERRUPT==1)
    app_send_offset = 0;
    spp_tx_retry_count = 0;

    if(wiced_is_timer_in_use(&app_tx_timer))
    wiced_stop_timer(&app_tx_timer);
#endif
}

/*
 * Process data received over EA session.  Return TRUE if we were able to allocate buffer to
 * deliver to the host.
 */
wiced_bool_t spp_rx_data_callback(uint16_t handle, uint8_t* p_data, uint32_t data_len)
{
//    int i;
//    wiced_bt_buffer_statistics_t buffer_stats[4];

//    wiced_bt_get_buffer_usage (buffer_stats, sizeof(buffer_stats));

//    WICED_BT_TRACE("0:%d/%d 1:%d/%d 2:%d/%d 3:%d/%d\n", buffer_stats[0].current_allocated_count, buffer_stats[0].max_allocated_count,
//                   buffer_stats[1].current_allocated_count, buffer_stats[1].max_allocated_count,
//                   buffer_stats[2].current_allocated_count, buffer_stats[2].max_allocated_count,
//                   buffer_stats[3].current_allocated_count, buffer_stats[3].max_allocated_count);
//    buffer_report("spp_rx_data_callback");

//    wiced_result_t wiced_bt_get_buffer_usage (&buffer_stats, sizeof(buffer_stats));

    spp_rx_bytes += data_len;

    WICED_BT_TRACE("%s handle:%d len:%d %02x-%02x, total rx %d\n", __FUNCTION__, handle, data_len, p_data[0], p_data[data_len - 1], spp_rx_bytes);

#if LOOPBACK_DATA
    return wiced_bt_spp_send_session_data(handle, p_data, data_len);
#else
    return WICED_TRUE;
#endif
}

/*
 * spp_bt_remote_name_callback
 */
static void spp_bt_remote_name_callback(wiced_bt_dev_remote_name_result_t *p_remote_name_result)
{
    WICED_BT_TRACE("Pairing with: BdAddr:%B Status:%d Len:%d Name:%s\n",
            p_remote_name_result->bd_addr, p_remote_name_result->status,
            p_remote_name_result->length, p_remote_name_result->remote_bd_name);
}

/*
 * Write NVRAM function is called to store information in the NVRAM.
 */
int app_write_nvram(int nvram_id, int data_len, void *p_data)
{
    wiced_result_t  result;
    int             bytes_written = wiced_hal_write_nvram(nvram_id, data_len, (uint8_t*)p_data, &result);

    WICED_BT_TRACE("NVRAM ID:%d written :%d bytes result:%d\n", nvram_id, bytes_written, result);
    return (bytes_written);
}

/*
 * Read data from the NVRAM and return in the passed buffer
 */
int app_read_nvram(int nvram_id, void *p_data, int data_len)
{
    uint16_t        read_bytes = 0;
    wiced_result_t  result;

    if (data_len >= sizeof(wiced_bt_device_link_keys_t))
    {
        read_bytes = wiced_hal_read_nvram(nvram_id, sizeof(wiced_bt_device_link_keys_t), p_data, &result);
        WICED_BT_TRACE("NVRAM ID:%d read out of %d bytes:%d result:%d\n", nvram_id, sizeof(wiced_bt_device_link_keys_t), read_bytes, result);
    }
    return (read_bytes);
}

#if SEND_DATA_ON_INTERRUPT
/*
 * Test function which sends as much data as possible.
 */
void app_send_data(void)
{
    int i;
    wiced_bool_t ret;
    wiced_bt_dev_cancel_sniff_mode(peer_addr);
    while ((spp_handle != 0) && (app_send_offset != APP_TOTAL_DATA_TO_SEND))
    {
        int bytes_to_send = app_send_offset + SPP_MAX_PAYLOAD < APP_TOTAL_DATA_TO_SEND ? SPP_MAX_PAYLOAD : APP_TOTAL_DATA_TO_SEND - app_send_offset;
        ret = wiced_bt_spp_can_send_more_data(spp_handle);
        if(!ret)
        {
            // buffer_report(" app_send_data can't send");
            // WICED_BT_TRACE(" ! return from wiced_bt_spp_can_send_more_data\n");
            break;
        }
        for (i = 0; i < bytes_to_send; i++)
        {
            app_send_buffer[i] = app_send_offset + i;
        }
        ret = wiced_bt_spp_send_session_data(spp_handle, app_send_buffer, bytes_to_send);
        if(ret != WICED_TRUE)
        {
            // WICED_BT_TRACE(" ! return from wiced_bt_spp_send_session_data\n");
            break;
        }
        app_send_offset += bytes_to_send;
        spp_tx_retry_count = 0;
    }
    // Check if we were able to send everything
    if (app_send_offset < APP_TOTAL_DATA_TO_SEND)
    {
        if(spp_tx_retry_count >= MAX_TX_RETRY)
        {
		WICED_BT_TRACE("Reached max tx retries! Terminating transfer!\n");
		WICED_BT_TRACE("Make sure peer device is providing us credits\n");
		app_send_offset = 0;
        }
        else
        {
            WICED_BT_TRACE("wiced_start_timer app_tx_timer %d\n", app_send_offset);
		wiced_start_timer(&app_tx_timer, TX_RETRY_TIMEOUT);
		spp_tx_retry_count++;
        }
    }
    else
    {
        uint32_t time_tx = clock_SystemTimeMicroseconds64() / 1000 - time_start;
        WICED_BT_TRACE("sent %d in %dmsec (%dKbps)\n", APP_TOTAL_DATA_TO_SEND, time_tx, APP_TOTAL_DATA_TO_SEND * 8 / time_tx);
        app_send_offset = 0;
        spp_tx_retry_count = 0;
    }
}

/*
 * Test function which start sending data.
 */
void app_interrupt_handler(void *data, uint8_t port_pin)
{
    WICED_BT_TRACE("gpio_interrupt_handler pin:%d send_offset:%d\n", port_pin, app_send_offset);
    time_start = clock_SystemTimeMicroseconds64() / 1000;

     /* Get the status of interrupt on P# */
    if (wiced_hal_gpio_get_pin_interrupt_status(BUTTON_GPIO))
    {
        /* Clear the GPIO interrupt */
        wiced_hal_gpio_clear_pin_interrupt_status(BUTTON_GPIO);
    }
    // If we are already sending data, do nothing
    if (app_send_offset != 0)
        return;

    app_send_data();
}

/*
 * The timeout function is periodically called while we are sending big amount of data
 */
void app_tx_ack_timeout(TIMER_PARAM_TYPE param)
{
    app_send_data();
}
#endif


#ifdef HCI_TRACE_OVER_TRANSPORT
/*
 *  Pass protocol traces up over the transport
 */
void app_trace_callback(wiced_bt_hci_trace_type_t type, uint16_t length, uint8_t* p_data)
{
#if BTSTACK_VER >= 0x03000001
    wiced_transport_send_hci_trace( type, p_data, length );
#else
    wiced_transport_send_hci_trace(host_trans_pool, type, length, p_data);
#endif
}
#endif

 

 

728x90
728x90

REF. 

https://interrupt.memfault.com/blog/ble-throughput-primer#:~:text=For%20Bluetooth%204.0%2C%20the%20BLE,be%20encoded%20in%20each%20symbol

 

A Practical Guide to BLE Throughput

A community and blog for embedded software makers

interrupt.memfault.com

https://novelbits.io/bluetooth-5-speed-maximum-throughput/

 

Bluetooth 5 speed: How to achieve maximum throughput for your BLE application

In this second post in the series on Bluetooth 5, we cover the new feature of 2x speed and how to achieve maximum data throughput for your BLE application.

novelbits.io

 

Why is it impossible to achieve the theoretical speeds of BLE?

The data rates of 1 Mbps (LE 1M PHY), 2 Mbps (LE 2M PHY), 125 kbps and 500 kbps (both using the LE Coded PHY with S=8 and S=2, respectively) are the rates at which the radio transmits data, but this is not achievable for the application throughput due to the following reasons:

  • Limit on the number of packets per connection interval
  • Inter Frame Space (IFS) delay between packets (150 us)
  • Empty packets required to be sent from a device even if no data is available for transmission
  • Packet overhead – not all bytes in a packet are used for payload

In order to better understand these factors and understand what impacts application throughput, we have to take a deeper look at the packet format. The following figure shows what LE 1M PHY and 2M PHY data packets look like:

The part we’re interested in (and the one that really defines the application data) is the ATT Payload. As you can see from the figure, there are a number of overhead bytes that are used by each layer in Bluetooth Low Energy.

  • In 4.0 and 4.1, the maximum ATT Payload is 20 bytes.
  • In 4.2 and 5.0, a new feature called Data Length Extensions (DLE) allows the ATT Payload to hold up to 244 bytes of data.

 

Factors that impact/determine the data throughput

There are a few factors that impact the data throughput of a BLE application. The most common are:

  • PHY being used (LE 1M vs. LE 2M vs. LE Coded (S=2 or S=8))
  • Connection interval
  • Maximum number of packets per connection interval
  • ATT Maximum Transmission Unit (ATT MTU)
  • Data Length Extension (DLE)
  • Operation type: Write with response vs. write without response, Indications vs. Notifications
  • Inter Frame Space (IFS): time gap between consequent packets (150 us)
  • Transmission of empty packets
  • Packet overhead – not all bytes, in a packet, are used for the application payload

Calculating your application data throughput

The big question is: how do we calculate our application throughput?

As we mentioned before, there are a few variables that impact the data throughput:

  • Bluetooth version & PHY used
  • DLE: Data Length Extensions – enabled or not
  • ATT MTU value
  • Connection interval
  • Maximum number of packets per connection event
  • Operation (writes with responses vs. writes without responses, and notification vs. indication)
  • Inter Frame Space (IFS): 150 microseconds

The Link Layer (LL) Packet

All data during a BLE connection is sent via Link Layer (LL) packets. All higher level messages are packed within Data Payloads of LL Packets. Below is what a LL Packet sending data looks like (each tick mark represents 1 byte):

 

NOTE: The astute reader may note that Data Payload can be up to 251 bytes. This however is an optional feature known as “LE Data Packet Length Extension” which we will explore in more detail below

Maximum Link Layer Data Payload Throughput

With the three rules we mentioned about transmissions on the Bluetooth Radio in mind, let’s take a look at the procedure to transmit a maximally sized LL packet.

  • Side A sends a maximum size LL data packet (27 bytes of data in a 41 byte payload) which takes 328μs (41 bytes * 8 bits / byte * 1Mbps) to transmit
  • Side B receives the packet and waits T_IFS (150μs)
  • Side B ACKs the LL packet it received in 80μs (0 bytes of data)
  • Side A waits T_IFS before sending any more data

Here’s an example exchange of two packets of data in one Connection Event:

The time it takes to transmit one packet can be computed as:

328μs data packet + 150μs T_IFS + 80μs ACK + 150μs T_IFS = 708μs

During this time period, 27 bytes of actual data can be transmitted which takes 216μs.

This yields a raw data throughput of:

(216μs / 708μs) * 1Mbps = 305,084 bits/second = ~0.381 Mbps

The Link Layer (LL) Packet

All data during a BLE connection is sent via Link Layer (LL) packets. All higher level messages are packed within Data Payloads of LL Packets. Below is what a LL Packet sending data looks like (each tick mark represents 1 byte):

NOTE: The astute reader may note that Data Payload can be up to 251 bytes. This however is an optional feature known as “LE Data Packet Length Extension” which we will explore in more detail below

Maximum Link Layer Data Payload Throughput

With the three rules we mentioned about transmissions on the Bluetooth Radio in mind, let’s take a look at the procedure to transmit a maximally sized LL packet.

  • Side A sends a maximum size LL data packet (27 bytes of data in a 41 byte payload) which takes 328μs (41 bytes * 8 bits / byte * 1Mbps) to transmit
  • Side B receives the packet and waits T_IFS (150μs)
  • Side B ACKs the LL packet it received in 80μs (0 bytes of data)
  • Side A waits T_IFS before sending any more data

Here’s an example exchange of two packets of data in one Connection Event:

The time it takes to transmit one packet can be computed as:

328μs data packet + 150μs T_IFS + 80μs ACK + 150μs T_IFS = 708μs

During this time period, 27 bytes of actual data can be transmitted which takes 216μs.

This yields a raw data throughput of:

(216μs / 708μs) * 1Mbps = 305,084 bits/second = ~0.381 Mbps

 

Maximum throughput over GATT

The Attribute Protocol Handle Value Notification is the best way for a server to stream data to a client when using GATT. The Opcode Overhead for this operation is 2 bytes. That means there are 3 bytes of ATT packet overhead and 4 bytes of L2CAP overhead for each ATT payload. We can determine the max ATT throughput by taking the maximum raw Link Layer throughput and multiplying it by the efficiency of the ATT packet:

ATT Throughput = LL throughput * ((MTU Size - ATT Overhead) / (L2CAP overhead + MTU Size))

Tabulating this information for a couple common MTU sizes we get:

MTU size (bytes) Throughput (Mbps)
23 (default) 0.226
185 (iOS 10 max) 0.294
512 0.301

LE Data Packet Length Extension (BT v4.2)

As part of the 4.2 Bluetooth Core Specification revision, a new feature known as LE Data Packet Length Extension was added 4. This optional feature allows for a device to extend the length of the Data Payload in a Link Layer packet from 27 up to 251 bytes! This means that instead of sending 27 bytes of data in a 41 byte payload, 251 bytes of data can now be sent in a 265 byte payload. Furthermore, we can send a lot more data with fewer T_IFS gaps. Let’s take a look at what exchanging a maximally sized packet looks like:

We can calculate the raw data throughput and see that this modification yields greater than a 2x improvement on the maximum raw data throughput which can be achieved!

251 bytes / 2500μs = 100.4 kBytes/sec = ~0.803 Mbps

 

LE 2M PHY (BT v5.0)

As part of the 5.0 Bluetooth Core Specification revision, a new feature known as “LE 2M PHY”5 was added. As you may recall in the section above, we discussed how the BLE Radio is capable of transmitting 1 symbol per μs for a bitrate of 1Mbps. This revision to the Bluetooth Low Energy Physical Layer (PHY), allows for a symbol rate of 2Mbps. This means we can transmit each individual bit in half the time. However, the 150μs IFS is still needed between transmissions. Let’s take a look on how this impacts the throughput when sending packets that are using the data packet length extension feature:

We can calculate this throughput and see the modification yields almost a 4x improvement over the original maximal raw data speed that could be achived with BLE 4.0:

251 bytes / 1400μs = 179.3 kBytes/sec = ~1.434 Mbps

 

LE Coded PHY (BT v5.0)

The “LE Coded PHY” feature, also introduced in the 5.0 Spec 5 provides a way to extend the range of BLE at the cost of speed. The feature works by encoding a bit across multiple symbols on the radio. This makes the bits being transmitted more resilient to noise. There are two operation modes where either two symbols or eight symbols can be used to encode a single bit. This effectively reduces the radio bitrate to 500 kbps or 125kbps, respectively.

 

 

Determine the time it takes to send one data packet and the empty packet from the receiver.

The time during which one data packet can be sent will include the following:
Data_Packet_Time = Time to transmit empty packet + IFS + Time to transmit the actual data packet + IFS.

An empty packet transmission time can be calculated as follows:
Time to transmit empty packet = empty packet size / raw data rate

An empty packet will contain the following fields:
Preamble + Access Address + LL Header + CRC.
For 1M PHY, Preamble will be 1 byte, and so the total size of the empty packet = 1 + 4 + 2 + 3 bytes = 10 bytes = 
80 bits.

(for 2M PHY, the size of an empty packet will be 88 bits since the Premable is 2 bytes instead of 1 byte).
Based on this, the time to transmit an empty 1M PHY packet will be:
Time to transmit empty packet = empty packet size / raw data rate = 80 bits/ 1 Megabits per second =
80 micro seconds

A data packet will contain all fields listed in the packet format diagram with the exception of the MIC field (encryption disabled).
Time to transmit data packet = data packet size / raw data rate

If we have DLE enabled and the ATT MTU is equal to the maximum bytes allowed in one packet: 247 bytes, then we can calculate the data packet size as:
Data packet size = 1 + 4 + 2 + 4 + 247 + 3 bytes = 265 bytes = 265*8 bits = 2088 bits
Time to transmit data  packet = 2088 bits / 1 Mbps = 
2,088 micro seconds

Data_Packet_Time = Time to transmit empty packet + IFS + Time to transmit the actual data packet + IFS = 80 + 2*150 + 2088 = 2,468 microsecs

For comparison, in the case of 2M PHY, it would be:
Data_Packet_Time = Time to transmit empty packet + IFS + Time to transmit the actual data packet + IFS = 88/2 + 2*150 + (2 + 4 + 2 + 4 + 247 + 3)*8/2 = 
1,392 microsecs

When DLE is enabled and the ATT MTU is set to less than 247, we end up with more overhead (since now data larger than the ATT MTU gets split up into more packets). For example, say we have the ATT MTU set to 158, then in order to transfer 244 bytes of application data, we will need two packets instead of one, causing the throughput to go down due to the increased byte overhead as well as the increased IFS between the packets. In another scenario, we could have DLE disabled (Payload size up to 27 bytes) and the ATT MTU greater than 27 bytes. Here, this will also result in more packets needed to be sent for the same amount of data, causing the throughput to go down.
Note: The same method for calculating the data and empty packet sizes that we used above can be used for the LE Coded PHY.

 

728x90

+ Recent posts