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

Official link: https://valgrind.org/

 

Valgrind Home

Valgrind is an instrumentation framework for building dynamic analysis tools. There are Valgrind tools that can automatically detect many memory management and threading bugs, and profile your programs in detail. You can also use Valgrind to build new tool

valgrind.org

 

Install:

sudo apt install valgrind  # Ubuntu, Debian, etc.
sudo yum install valgrind  # RHEL, CentOS, Fedora, etc.
sudo pacman -Syu valgrind  # Arch, Manjaro, Garuda, etc

 

 

내부적으로 GDB를 사용하기 때문에 addr2line같은 것들이 제대로 동작해야 한다.

이전 포스팅에서 추가했던 secure compile option들을 넣으면 안된다.

대신 -g를 추가하여 debugging이 가능하도록 해야 한다.

https://bluelimn.tistory.com/entry/secure-compile

 

secure compile

checksec를 통해 secure compile 정보를 알 수 있다. https://github.com/slimm609/checksec.sh GitHub - slimm609/checksec.sh: Checksec.sh Checksec.sh. Contribute to slimm609/checksec.sh development by creating an account on GitHub. github.com 우선 3

bluelimn.tistory.com

 

ref: https://stackoverflow.com/questions/5134891/how-do-i-use-valgrind-to-find-memory-leaks

valgrind --leak-check=full \
         --show-leak-kinds=all \
         --track-origins=yes \
         --verbose \
         --log-file=valgrind-out.txt \
         ./executable exampleParam1

 

728x90
728x90

MyComboBox.java

import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.JTextComponent;
import javax.swing.undo.*;

public class MyComboBox extends JComboBox {


	final UndoManager undoMgr = new UndoManager();
	
	public MyComboBox() {
		super();
        init();
    }
	
    public final static String UNDO_ACTION = "Undo";

    public final static String REDO_ACTION = "Redo";

    private void init()
    {

    	setEditable(true);

        getEditor().getEditorComponent().addKeyListener(new KeyAdapter() {
		    @Override
		    public void keyReleased(KeyEvent event) {
		        if (event.getKeyCode() == KeyEvent.VK_F3)
		        {
		        	addItem((String)((JTextComponent)getEditor().getEditorComponent()).getText());
		        }
		        else if (event.getKeyCode() == KeyEvent.VK_F4)
		        {
		        	removeItemAt(getSelectedIndex());
		        }
		    }
		    public void keyPressed(KeyEvent e) {
		        if (e.getKeyCode() == KeyEvent.VK_Z && e.isControlDown()) {
		            if (undoMgr.canUndo()) {
		            	undoMgr.undo();
		            }
		        } else if (e.getKeyCode() == KeyEvent.VK_Y && e.isControlDown()) {
		            if (undoMgr.canRedo()) {
		            	undoMgr.redo();
		            }
		        }
		    }
		});

        // Add listener for undoable events
    	(((JTextField)getEditor().getEditorComponent()).getDocument()).addUndoableEditListener(new UndoableEditListener() {
            public void undoableEditHappened(UndoableEditEvent pEvt) {
                undoMgr.addEdit(pEvt.getEdit());
            }
        });

    }

}

 

 

MyTextField.java

import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.JTextComponent;
import javax.swing.undo.*;

public class MyTextField extends JTextField {
    public MyTextField() {
        final UndoManager undoMgr = new UndoManager();

        // Add listener for undoable events
        getDocument().addUndoableEditListener(new UndoableEditListener() {
            public void undoableEditHappened(UndoableEditEvent pEvt) {
                undoMgr.addEdit(pEvt.getEdit());
            }
        });

        // Add undo/redo actions
        getActionMap().put(UNDO_ACTION, new AbstractAction(UNDO_ACTION) {
            public void actionPerformed(ActionEvent pEvt) {
                try {
                    if (undoMgr.canUndo()) {
                        undoMgr.undo();
                    }
                } catch (CannotUndoException e) {
                    e.printStackTrace();
                }
            }
        });
        getActionMap().put(REDO_ACTION, new AbstractAction(REDO_ACTION) {
            public void actionPerformed(ActionEvent pEvt) {
                try {
                    if (undoMgr.canRedo()) {
                        undoMgr.redo();
                    }
                } catch (CannotRedoException e) {
                    e.printStackTrace();
                }
            }
        });

        // Create keyboard accelerators for undo/redo actions (Ctrl+Z/Ctrl+Y)
        getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK),
            UNDO_ACTION);
        getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Y, InputEvent.CTRL_DOWN_MASK),
            REDO_ACTION);
    }
    
    public final static String UNDO_ACTION = "Undo";

    public final static String REDO_ACTION = "Redo";

    public static void makeUndoable(JTextComponent pTextComponent) {
        final UndoManager undoMgr = new UndoManager();

        // Add listener for undoable events
        pTextComponent.getDocument().addUndoableEditListener(new UndoableEditListener() {
            public void undoableEditHappened(UndoableEditEvent evt) {
                undoMgr.addEdit(evt.getEdit());
            }
        });

        // Add undo/redo actions
        pTextComponent.getActionMap().put(UNDO_ACTION, new AbstractAction(UNDO_ACTION) {
            public void actionPerformed(ActionEvent evt) {
                try {
                    if (undoMgr.canUndo()) {
                        undoMgr.undo();
                    }
                } catch (CannotUndoException e) {
                    e.printStackTrace();
                }
            }
        });
        pTextComponent.getActionMap().put(REDO_ACTION, new AbstractAction(REDO_ACTION) {
            public void actionPerformed(ActionEvent evt) {
                try {
                    if (undoMgr.canRedo()) {
                        undoMgr.redo();
                    }
                } catch (CannotRedoException e) {
                    e.printStackTrace();
                }
            }
        });

        // Create keyboard accelerators for undo/redo actions (Ctrl+Z/Ctrl+Y)
        pTextComponent.getInputMap().put(
            KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK), UNDO_ACTION);
        pTextComponent.getInputMap().put(
            KeyStroke.getKeyStroke(KeyEvent.VK_Y, InputEvent.CTRL_DOWN_MASK), REDO_ACTION);
    }
}
728x90

'Programming > JAVA잡기' 카테고리의 다른 글

자바 RMI (Remote Method Invovation) 사용하기  (0) 2008.09.23
자바 컴포넌트 기술(JDBC, JSP,JFC...)  (0) 2008.03.13
why JAVA?  (0) 2008.03.13
728x90

checksec를 통해 secure compile 정보를 알 수 있다.

https://github.com/slimm609/checksec.sh

 

GitHub - slimm609/checksec.sh: Checksec.sh

Checksec.sh. Contribute to slimm609/checksec.sh development by creating an account on GitHub.

github.com

 

우선 3가지 방향으로 compile을 해봤다.

test$ gcc pie_test.c -o default_pie

test$ gcc -static pie_test.c -o without_pie

test$ gcc -pie -fPIE pie_test.c -o with_pie

 

x86_64에서는 default로 PIE를 지원하고 있다.

Arm에서는 어떤지 알아보자

 

test$ aarch64-none-linux-gnu-gcc pie_test.c -o default_arm_pie
test$ aarch64-none-linux-gnu-gcc pie_test.c -static -o static_arm_pie
test$ aarch64-none-linux-gnu-gcc pie_test.c -fPIE -pie -o with_pie_arm_pie

Default로 PIE가 지원하지 않음을 알 수 있다. PIE를 위해서는 -fPIE -pie가 필요하다.

-fPIE는 compile option이고 -pie는 linker option이라고 한다.

 

stack canary에 대해 확인해보자

 

canary를 지원하기 위해서는 -fstack-protector-all를 추가해야 한다.

 

FORTIFY 추가: -D_FORTIFY_SOURCE=2

이건 -O를 함께 요구하기도 한다.

 

RELRO로 한번 넣어보자.:Relocation Read-Only : -Wl,-z,relro,-z,now

test$ aarch64-none-linux-gnu-gcc pie_test.c -fPIE -pie -fstack-protector-all -O -D_FORTIFY_SOURCE=2 -Wl,-z,relro,-z,now -o with_fortify

 

Symbols : -s

test$ aarch64-none-linux-gnu-gcc pie_test.c -fPIE -pie -fstack-protector-all -O -D_FORTIFY_SOURCE=2 -Wl,-z,relro,-z,now  -s -o with_fortify

 

* NX: "No eXecute" 영역이 적용되어 있는지 여부를 나타냅니다. 이 기능은 데이터 섹션에서 실행할 수 있는 코드 실행을 막아서, 공격자가 바이너리에 대한 취약점을 악용하는 것을 방지합니다.

* RPATH: ELF 바이너리에서 실행 시 참조할 라이브러리 경로를 지정하는데 사용됩니다. RPATH는 보안 위험이 발생할 수 있는 기능 중 하나로, 바이너리가 취약점을 가지고 있는 경우, 공격자가 RPATH를 이용하여 공격할 수 있습니다.

* RUNPATH: RPATH와 비슷한 역할을 하지만, 라이브러리 경로를 찾는 방법이 다릅니다. RUNPATH는 LD_LIBRARY_PATH와 같이 컴파일러나 링커에서 지정된 환경 변수에서 라이브러리 경로를 찾습니다.

* FORTIFY: FORTIFY는 C 라이브러리 함수를 보안 강화된 버전으로 대체하는 방식으로, 버퍼 오버플로우나 포맷 문자열 취약점 등의 보안 문제를 방지합니다.

* Symbols: ELF 바이너리에서 전역 심볼이 제대로 제한되었는지 여부를 나타냅니다. 이 기능은 공격자가 ELF 바이너리 내부의 함수나 변수의 위치를 찾아서 악용하는 것을 방지합니다. 따라서, 이 기능이 활성화되어 있으면 ELF 바이너리가 더욱 안전하게 실행될 수 있습니다.

* RELRO: RELRO는 "RELocation Read-Only"의 약자로, 바이너리의 메모리 매핑을 보호하는 기능입니다. 바이너리가 실행될 때, 공유 라이브러리나 동적 연결된 라이브러리들을 메모리에 로드합니다. 그런데 이러한 라이브러리들이 바이너리의 일부로 취급될 경우, 메모리 매핑이 변경될 수 있습니다. 이 때, 공격자가 바이너리의 실행 흐름을 변경하여 악용할 수 있습니다. 이를 방지하기 위해 RELRO 기능을 사용하여 바이너리의 메모리 매핑을 읽기 전용으로 설정합니다. RELRO 기능은 Partial RELRO와 Full RELRO가 있으며, Full RELRO는 보안성이 높아 추천되는 옵션입니다.

728x90

+ Recent posts