无线连接知识库

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 

Wireless Connectivity Knowledge Base

讨论

排序依据:
Overview Bluetooth Low Energy offers the ability to broadcast data in format of non-connectable advertising packets while not being in a connection. This GAP Advertisement is widely known as a beacon and is used in today’s IoT applications in different forms. This article will present the current beacon format in our demo application from the KW40Z software package and how to create the most popular beacon formats on the market. The advertising packet format and payload are declared in the gAppAdvertisingData structure from app_config.c. This structure points to an array of AD elements, advScanStruct: static const gapAdStructure_t advScanStruct[] = {   {     .length = NumberOfElements(adData0) + 1,     .adType = gAdFlags_c,     .aData = (void *)adData0   },    {     .length = NumberOfElements(adData1) + 1,     .adType = gAdManufacturerSpecificData_c,     .aData = (void *)adData1   } }; Due to the fact that all beacons use the advertising flags structure and that the advertising PDU is 31 bytes in length (Bluetooth Low Energy v4.1), the maximum payload length is 28 bytes, including length and type for the AD elements. The AD Flags element is declared as it follows: static const uint8_t adData0[1] =  { (gapAdTypeFlags_t)(gLeGeneralDiscoverableMode_c | gBrEdrNotSupported_c) }; The demo application uses a hash function to generate a random UUID for the KW40Z default beacon. This is done in BleApp_Init: void BleApp_Init(void) {     sha1Context_t ctx;         /* Initialize sha buffer with values from SIM_UID */     FLib_MemCopy32Unaligned(&ctx.buffer[0], SIM_UIDL);     FLib_MemCopy32Unaligned(&ctx.buffer[4], SIM_UIDML);     FLib_MemCopy32Unaligned(&ctx.buffer[8], SIM_UIDMH);     FLib_MemCopy32Unaligned(&ctx.buffer[12], 0);          SHA1_Hash(&ctx, ctx.buffer, 16);         /* Updated UUID value from advertising data with the hashed value */     FLib_MemCpy(&gAppAdvertisingData.aAdStructures[1].aData[3], ctx.hash, 16); } When implementing a constant beacon payload, please bear in mind to disable this code section. KW40Z Default Beacon The KW40Z software implements a proprietary beacon with the maximum ADV payload and uses the following Manufacturer Specific Advertising Data structure of 26 bytes. This is the default implementation of the beacon demo example from the KW40Z Connectivity Software package. static uint8_t adData1[26] = {     /* Company Identifier*/     0xFF, 0x01     /* Beacon Identifier */     0xBC,     /* UUID */                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,                                   /* A */                     0x00, 0x00,     /* B */                     0x00, 0x00,     /* C */                     0x00, 0x00,     /* RSSI at 1m */            0x1E}; iBeacon iBeacon is a protocol designed by Apple. It uses a 20 byte payload that consists of the following identifying information [1] : To advertise an iBeacon packet, the user needs to change the second AD element, adData1, like below: static uint8_t adData1[25] = {                                0x4C, 0x00,                                   0x02, 0x15,         /* UUID */             0xD9, 0xB9, 0xEC, 0x1F, 0x39, 0x25, 0x43, 0xD0, 0x80, 0xA9, 0x1E, 0x39, 0xD4, 0xCE, 0xA9, 0x5C,         /* Major Version */    0x00, 0x01         /* Minor Version */    0x00, 0x0A,                                0xC5}; AltBeacon AltBeacon is an open specification designed for proximity beacon advertisements [2]. It also uses a Manufacturer Specific Advertising Data structure: To advertise an AltBeacon packet, the user needs to change the second AD element, like below: static uint8_t adData1[26] = {     /* MFG ID*/         0xFF, 0x01,     /* Beacon Code */   0xBE, 0xAC,     /* Beacon ID */     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04,     /* Ref RSSI*/       0xC5,     /* MFG RSVD*/       0x00}; Eddystone™ Eddystone™ is an open Bluetooth® Smart beacon format from Google [3]. It offers three data type packets: Eddystone™-UID Eddystone™-URL Eddystone™-TLM Eddystone™ uses two advertising structures: Complete List of 16-bit Service UUIDs structure, which contains the Eddystone Service UUID (0xFEAA). Service Data structure, which also contains the Eddystone™ Service UUID (0xFEAA). Thus, advScanStruct will now have 3 elements: static const gapAdStructure_t advScanStruct[] = {   {     .length = NumberOfElements(adData0) + 1,     .adType = gAdFlags_c,     .aData = (void *)adData0   },    {     .length = NumberOfElements(adData1) + 1,     .adType = gAdComplete16bitServiceList_c,     .aData = (void *)adData1   },   {     .length = NumberOfElements(adData2) + 1,     .adType = gAdServiceData16bit_c,     .aData = (void *)adData2   } }; The complete List of 16-bit Service UUIDs element will look like: static const uint8_t adData1[2] =  { 0xAA, 0xFE }; Eddystone™-UID Eddystone™-UID broadcasts a unique 16-bit Beacon ID to identify a particular device in a group. The Service Data block has the following structure: To implement this, the user needs to add a third AD element, as follows: static uint8_t adData2[22] = {     /* ID */ 0xAA, 0xFE,     /* Frame Type */    0x00,     /* Ranging Data */  0xEE,     /* Namespace */     0x8B, 0x0C, 0xA7, 0x50, 0x09, 0x54, 0x77, 0xCB, 0x3E, 0x77,     /* Instance */      0x00, 0x00, 0x00, 0x00, 0x00, 0x01,     /* RFU */           0x00, 0x00}; Eddystone™-URL Eddystone™-URL broadcasts a compressed URL. The Service Data block has the following structure: In this example, we will implement a beacon which will advertise NXP’s webpage, http://www.nxp.com. To implement this, the user needs to add a third AD element, as follows: static const uint8_t adData2[9] = {     /* ID */ 0xAA, 0xFE,     /* Frame Type */    0x10,     /* TX Power */      0xEE,     /* URL scheme */    0x00,     /* Encode URL */    'n', 'x, 'p', 0x07}; Eddystone™-TLM Eddystone™-TLM broadcasts telemetry data about the beacon device operation. The Service Data block has the following structure: To implement this, the user needs to add a third AD element, as follows: static uint8_t adData2[16] = {     /* ID */ 0xAA, 0xFE,     /* Frame Type */    0x20,     /* TLM Version */   0x00,     /* VBATT */        0x00, 0x00,     /* TEMP */         0x00, 0x00,     /* ADV_CNT */      0x00, 0x00, 0x00, 0x00,     /* SEC_CNT */      0x00, 0x00, 0x00, 0x00};
查看全文
Introduction Over The Air Programming (OTAP) is a Bluetooth LE custom NXP's service that provides a solution to upgrade the software running in the microcontroller. This document guides to load a new software image in a KW38 device through (Over The Air Programming) OTAP Bluetooth LE service. Software Requirements MCUXpresso IDE or IAR Embedded Workbench IDE. FRDM-KW38 SDK. IoT Toolbox App, available for Android and iOS. You can also download the APK of the IoT Toolbox App from this post: IoT Toolbox for Android  Hardware Requirements FRDM-KW38 board. A smartphone with IoT Toolbox App. KW38 Flash Memory Used by the OTAP Client Software During the Update Process By default, the 512KB KW38 flash memory is partitioned into: One 256KB Program Flash array (P-Flash) divided into 2KB sectors with a flash address range from 0x0000_0000 to 0x0003_FFFF. One 256KB FlexNVM array divided into 2KB sectors with address range from 0x1000_0000 to 0x1003_FFFF. Alias memory with address range from 0x0004_0000 to 0x0007_FFFF. Writes or reads at the Alias memory modifies or returns the FlexNVM content, respectively. In other words, Alias memory is another way to refer to FlexNVM memory using different addresses. The following statements simplify how does the OTAP service work:   The OTAP application consists of two independent parts, OTAP bootloader, and OTAP client. The OTAP bootloader verifies if there is a new image available in the OTAP client to reprogram the device. The OTAP client software, on the other hand, provides the Bluetooth LE custom service needed to communicate the OTAP client device (device to be reprogrammed) with the OTAP server device (device that contains the image to reprogram the OTAP client device). Therefore, to prepare the software for the first time, the OTAP client device needs to be programmed twice, first with the OTAP bootloader, and then with the OTAP client software. The mechanism created to have two different software coexisting in the same device is storing each one in different memory regions. This is achieved by indicating to the linker file different memory regions on each individual software. For the KW38 device, the OTAP bootloader has reserved an 8KB slot from 0x0000_0000 to 0x0000_1FFF, thus the rest of the memory is reserved, among other things, by the OTAP client software.     When generating the new image file for the OTAP client device, we need to specify to the linker file that the code will be placed with an offset of 8KB (as the OTAP client software does), since these address range must be preserved to do not overwrite the OTAP bootloader. The new application should also contain the bootloader flags at the corresponding address to work properly (later we will return to this point).     While OTAP client and OTAP server devices are connected, and the download is in progress, the OTAP server device sends the image packets (known as chunks) to the OTAP client device via Bluetooth LE. The OTAP client device can store these chunks, in the external SPI flash (which is already populated on the FRDM-KW38) or in the on-chip FlexNVM region. The destination for these chunks is selectable in the OTAP client software (This post will give the instructions to modify the destination).     When the transfer of the image has finished, and all chunks were sent from the OTAP server device to the OTAP client device, the OTAP client software writes information such as the source of the software update (either external flash or FlexNVM) in a portion of memory known as bootloader flags. Then the OTAP client performs a software reset on the MCU to execute the OTAP bootloader code. Then, the OTAP bootloader code reads the bootloader flags to get the information needed to reprogram the device with the new application. See the following flow diagram which explains the flow of both applications.   Because the new application was built with an offset of 8KB, the OTAP bootloader programs the device starting from the 0x0000_2000 address, so, in consequence, the OTAP client application is overwritten by the new image. Then, the OTAP bootloader moves the flow of the application to start the execution of the new code.     In practice, the boundary between the OTAP client software and the software update when FlexNVM storage is enabled described in statement 3 is not placed exactly in the boundary of the P-Flash and FlexNVM memory regions, moreover, these values might change depending on your linker settings. To know where is located the boundary, you should inspect the effective memory addressing in your project.        Configuring and Programming OTAP Client Software in IAR Embedded Workbench IDE As mentioned in the last section, to complete the software for OTAP implementation, there are required two software programmed in your FRDM-KW38, OTAP bootloader and OTAP client. This section guides you to program and configure the settings to choose between external or internal storage using the IAR Embedded Workbench IDE. 1- The first step is to program the OTAP bootloader in your KW38. Unzip your SDK and then locate the OTAP bootloader software in the following path: <KW38_SDK>\boards\frdmkw38\wireless_examples\framework\bootloader_otap\bm\iar\bootloader_otap.eww 2- Program the OTAP bootloader project on your board by clicking on the "Download and Debug" icon (Ctrl + D) . Once the KW38 was programmed and the debug session begun, abort the session (Ctrl + Caps Lock + D)  to stop the MCU safely. 3- At this point, you have programmed the OTAP bootloader in your KW38. The next is to program and configure the OTAP client software. Locate the OTAP client software at the following path: Freertos project version: <KW38_SDK>\boards\frdmkw38\wireless_examples\bluetooth\otac_att\freertos\iar\otap_client_att_freertos.eww Baremetal project version: <KW38_SDK>\boards\frdmkw38\wireless_examples\bluetooth\otac_att\bm\iar\otap_client_att_bm.eww 4- Then, configure the OTAP client to select external or internal storage. To select the external storage, follow the next steps (this is the default configuration in the SDK project): 4.1- Locate the "app_preinclude.h" header file in the source folder of your workspace. Search the "gEepromType_d" define and set its value to "gEepromDevice_AT45DB041E_c". /* Specifies the type of EEPROM available on the target board */ #define gEepromType_d gEepromDevice_AT45DB041E_c 4.2- Open the project options window (Alt + F7). Go to Linker->Config window and set "gUseInternalStorageLink_d=0".   To select the internal storage, follow the next steps: 4.1- Locate the "app_preinclude.h" header file in the source folder of your workspace. Search the "gEepromType_d" define and set its value to "gEepromDevice_InternalFlash_c". /* Specifies the type of EEPROM available on the target board */ #define gEepromType_d gEepromDevice_InternalFlash_c 4.2- Open the project options window (Alt + F7). Go to Linker->Config window and set "gUseInternalStorageLink_d=1".   5- Once you have configured the storage settings, save the changes in the project. Then program the software on your board by clicking on the "Download and Debug" icon (Ctrl + D)  . Once the KW38 was programmed and the debug session began, abort the session (Ctrl + Caps Lock + D)  to stop the MCU safely. Creating an SREC Image to Update the Software in OTAP Client in IAR Embedded Workbench IDE This section shows how to create an image compatible with OTAP to reprogram the KW38 OTAP Client using as a starting point, our wireless examples with IAR Embedded Workbench IDE. 1- Select any example from your SDK package in the Bluetooth folder and open it using the IAR IDE. Bluetooth examples are located in the following path: <KW38_SDK>\boards\frdmkw38\wireless_examples\bluetooth  In this example, we will use the glucose sensor project: <KW38_SDK>\boards\frdmkw38\wireless_examples\bluetooth\glucose_s\freertos\iar\glucose_sensor_freertos.eww 2- Open the project options window in IAR (Alt + F7). In Linker->Config window, edit the options to include the "gUseBootloaderLink_d=1" flag and update the "gEraseNVMLink_d=0" flag. When the gUseBootlaoderLink_d flag is true, it indicates to the linker file that the image must be addressed after the first flash sector, to do not overwrite the OTAP Bootloader software (as we stated previously). On the other hand, the gEraseNVMLink_d symbol is used to fill with a 0xFF pattern the unused NVM flash memory region. Disabling this flag, our software image will not contain this pattern, in consequence, the image reduces its total size and it improves the speed of the OTAP download and memory usage. 3- Go to "Output Converter" window. Deselect the "Override default" checkbox, then expand the "Output format" combo box and select "Motorola S-records" format. Click the "OK" button to finish. 4- Build the project. 5- Locate the S-Record file (.srec) in the following path, and save it to a known location on your smartphone. <KW38_SDK>\boards\frdmkw38\wireless_examples\bluetooth\glucose_s\freertos\iar\debug\glucose_sensor_freertos.srec Configuring and Programming OTAP Client Software in MCUXpresso IDE As mentioned in a previous section, to complete the software for OTAP implementation, there are required two software programmed in your FRDM-KW38, OTAP bootloader and OTAP client. This section guides you to program and configure the settings to choose between external or internal storage using the MCUXpresso IDE. 1- Open MCUXpresso IDE. Click on "Import SDK example(s)" in the "Quickstart Panel". 2- Select the FRDM-KW38 icon and click "Next >". 3- Import the OTAP bootloader project. It is located in "wireless_examples -> framework -> bootloader_otap -> bm -> bootloader_otap". Click on the "Finish" button. 4- Program the OTAP bootloader project on your board by clicking on the "Debug" icon  . Once the KW38 was programmed and the debug session begun, abort the session  (Ctrl + F2) to stop the MCU safely. 5- Repeat steps 1 to 3 to import the OTAP client software on MCUXpresso IDE. It is located at "wireless_examples -> bluetooth -> otac_att -> freertos -> otap_client_att_freertos" for freertos version, or "wireless_examples -> bluetooth -> otac_att -> bm -> otap_client_bm_freertos" if you prefer baremetal instead. 6- Then, configure the OTAP client to select external or internal storage. To select the external storage, follow the next steps (this is the default configuration in the SDK project): 6.1- Locate the "app_preinclude.h" file under the source folder in your workspace. Search the "gEepromType_d" define and set its value to "gEepromDevice_AT45DB041E_c". /* Specifies the type of EEPROM available on the target board */ #define gEepromType_d gEepromDevice_AT45DB041E_c 6.2- Navigate to "Project -> Properties -> C/C++ Build -> MCU settings -> Memory details". Edit the Flash fields as shown in the figure below, and leave intact the RAM. To select the internal storage, follow the next steps: 6.1- Locate the "app_preinclude.h" file under the source folder in your workspace. Search the "gEepromType_d" define and set its value to "gEepromDevice_InternalFlash_c". /* Specifies the type of EEPROM available on the target board */ #define gEepromType_d gEepromDevice_InternalFlash_c 6.2- Navigate to "Project -> Properties -> C/C++ Build -> MCU settings -> Memory details". Edit the Flash fields as shown in the figure below, and leave intact the RAM. 7- Once you have configured the storage settings, save the changes in the project. Then program the software on your board by clicking on the "Debug" icon  . Once the KW38 was programmed and the debug session begun, abort the session  (Ctrl + F2) to stop the MCU safely. Creating an SREC Image to Update the Software in OTAP Client in MCUXpresso IDE This section shows how to create an image compatible with OTAP to reprogram the KW38 OTAP Client using as a starting point, our wireless examples with MCUXpresso IDE. 1- Import any example from your SDK package in the Bluetooth folder as explained previously. Bluetooth examples are located in "wireless_examples -> bluetooth" folder in the SDK Import Wizard. This example will make use of the glucose sensor project in "wireless_examples -> bluetooth -> glucose_s -> freertos -> glucose_sensor_freertos". See the picture below. 2- Navigate to "Project -> Properties -> C/C++ Build -> MCU settings -> Memory details". Edit the Flash fields as shown in the figure below, and leave intact the RAM. The last fields indicate to the linker file that the image must be addressed after the first flash sector, to do not overwrite the OTAP bootloader software, as we stated in the introduction of this post. 3- Unzip your KW38 SDK package. Drag and drop the "main_text_section.ldt" linker script from the following path to the "linkscripts" folder on your workspace. The result must be similar as shown in the following figure. <KW38_SDK>\middleware\wireless\framework\Common\devices\MKW38A4\mcux\linkscript_bootloader\main_text_section.ldt 4- Open the "end_text.ldt" linker script file located in the linkscripts folder in MCUXpresso IDE. Locate the section shown in the following figure and remove "FILL" and "BYTE" statements. BYTE and FILL lines are used to fill with a 0xFF pattern the unused NVM flash memory region. Removing this code, our software image will not contain this pattern, in consequence, the image reduces its total size and it improves the speed of the OTAP download and memory usage. 5- Open the "app_preinclude.h" file, and define "gEepromType_d" as internal storage. This is a dummy definition needed to place the bootloader flags in the proper address, so this will not affect the storage method chosen before when you programmed the OTAP client and the OTAP bootloader software in your MCU. /* Specifies the type of EEPROM available on the target board */ #define gEepromType_d gEepromDevice_InternalFlash_c 6-  Include in your project, the "OtaSupport" folder and its files in the "framework" folder of your project. Include as well the "External" folder and its files in the "framework -> Flash" folder of your project. "OtaSupport" and "External" folders can be found in your SDK. You can easily drag those folders from your SDK download path and drop it into your workspace in MCUXpresso to include them. "OtaSupport" and "External" folders are located at: OtaSupport <KW38_SDK>middleware\wireless\framework\OtaSupport External <KW38_SDK>middleware\wireless\framework\Flash\External The result must look like the following picture:  7- Go to "Project -> Properties -> C/C++ Build -> Settings -> Tool Settings -> MCU C Compiler -> Includes". Click on the icon next to "Include paths" (See the picture below). A new window will be displayed, then click on the "Workspace" button. 8- Deploy the directory of the project in the "Folder selection" window, and select "framework -> Flash -> External -> interface" and "framework -> OtaSupport -> interface" folders. Click the "OK" button to save the changes. 9- Ensure that "OtaSupport" and "External" folders were imported in the "Include paths" window. Then save the changes by clicking on the "Apply and Close" button. 10- Save and build the project by clicking this icon  . Then, deploy the "Binaries" icon in your project. Click the right mouse button on the ".axf" file and select the "Binary Utilities -> Create S-Record" option. The S-Record file generated will be saved in the Debug folder in your workspace with ".s19" extension. Save the S-Record file in a known location on your smartphone.    Testing the OTAP Client with IoT Toolbox App This section explains how to test the OTAP client software using the IoT Toolbox App. 1- Open the IoT Toolbox App on your smartphone. Select OTAP and click "SCAN" to start scanning for a suitable OTAP Client device.  2- Press the ADV button (SW2) on your FRDM-KW38 board to start advertising. 3- Once your smartphone has found the FRDM-KW38 board, it will be identified as "NXP_OTAA". Connect your smartphone with this device. Then a new window will be displayed on your smartphone.  4- Click the "Open" button and search for the SREC software update. 5- Click "Upload" to start the transfer. Wait while the download is completed. A confirmation message will be displayed after a successful update.  6- Wait a few seconds until the software update was programmed on your MCU. The new code will start automatically.   Please let me know any questions about this topic.
查看全文
I got a question related to best practices to configure a GPIO if the pin is not used. To make it short, the recommendation is to leave the GPIO floating on the PCB and leave the GPIO in its "Default" state as shown in the Signal Multiplexing table in the Reference Manual. The Default state is either “Disabled” or an analog function.   Some Kinetis devices have analog only pins (PGAx/ADCx) while most have GPIO pins with analog functions (PTx/ADCx) or digital GPIO pins   Unused pins, whether analog only or GPIO, should be left floating. Analog only pins do not have input buffers that will cause shoot-through currents when the input floats. GPIO pins with analog functions default to analog functions, which disables the digital input buffer – no shoot-through current.   The digital GPIO pins default to "Disabled", which disables the input buffers - no shoot-through currents with floating inputs.   Finally, unused pins shall not be tied to VDD or VSS. Hence, when designing your board and there are some unused pins, leave them floating on the PCB and then make sure that the software leaves the GPIO in its Default state in the MUX register. 
查看全文
This document and the attached files are maintained up to date in collaboration with Dragos Musoiu. This document is a supplement for USB MSC device bootloader revision for FRDM-KL25Z (IAR) written by Kai Liu and describes the bootloader support for USB-KW24D512. How to use 1) Connect the USB-KW24D512 to the PC USB port; 2) Download the attached file ‘USB_KW24D512_MSD_Bootloader.bin’ to the flash memory of the MKW24D512 SiP following the next steps: Connect a J-Link programmer to the PC USB port (other than the one used for the USB-KW24D512 dongle); Navigate to your J-Link driver folder using a command console and type ‘jlink.exe’ followed by enter; After the apparition of the J-Link prompter, type ‘unlock kinetis’ followed by enter; Wait for the unlock command confirmation and after, type ‘device mkw24d512xxx5’ followed by enter; After the J-Link prompter appears type ‘loadbin USB_KW24D512_MSD_Bootloader.bin 0’ followed by enter; (Be sure you copied the ‘USB_KW24D512_MSD_Bootloader.bin’ file in the same directory with jlink.exe otherwise, type the command specifying the full path of the binary file); After the flashing process successfully finished type ‘exit’ followed by enter. 3) Reset or reconnect the USB-KW24D512; 4) The OS will prompt MSD device connecting and then BOOTLOADER drive will appear. The bootloader software was tested on Microsoft Windows 10, Microsoft Windows 8.1, Microsoft Windows 7, Ubuntu 14.04 and MAC operating systems. 5) Copy and paste any user application .SREC or .bin file into BOOTLOADER drive; 6) If a valid .SREC or .bin file was given, the board restarts and starts to run the user application. Please refer to the Notes section in order to create valid .SREC or .bin files. Note:            The bootloader has conditional jump to user application. The condition is the state of the SW1 button (PTC4). If the button is pressed (PTC4 grounded) during reset, the bootloader sequence will start, installing BOOTLOADER drive, as described before. Else if the button is released during reset, the SP and PC will be updated from address 0xC000. This means, the user application has to use a linker file which forces the application start address to 0xC000. If a valid SP and PC value is found at address 0xC000, the user application is launched. The bootloader application is located in the flash memory of the MKW24D512 SiP, from address 0x0000 to 0xBFFF, so the user application should not put any code in this memory region. Avoid using .SREC or .bin files having program bytes or fill patterns in the bootloader section. Attached files: USB_KW24D512_MSD_Bootloader.bin – bootloader binary file for USB-KW24D512; Pflash_512KB_0xC000.icf – IAR linker file for user application development; 802.15.4SnifferOnUSB.bin – user application demo binary file for KW24D512-USB. Be aware that the file ‘802.15.4SnifferOnUSB.srec’ is linked according to the above memory restrictions and is working only with the bootloader presented in this document.
查看全文
This document provides information on distance measurements depending of the Bluetooth LE data rate (1Mbps, 2Mbps, LR S=2 & LR S=8). The FRDM-KW38 boards are used to perform the measurements. Results are similar on KW37 and KW39.  
查看全文
This document describes how to add additional cluster to the Router application in the JN-AN-1217 ZigBee 3.0 Base Device Application Note. The Router application's main endpoint contains Basic, Groups, Identify and OnOff server. The steps below describe how to add two clusters to Router: Temperature Measurement server and OnOff client. Note that these changes only go as far as making the new clusters added and discoverable, no functionality has been added to these clusters.  Common/Source/app.zpscfg The first step is to update the ZigBee PRO Stack Configuration file to add the new clusters (OnOff Client, Temperature Measurement Server) to the Router application endpoint. The HA profile already contains few clusters but Temperature Measurement cluster was added:   The OnOff client was already present in Router endpoint but the Temperature Measurement cluster was then added into Router application endpoint:   Router/Build/Makefile For cluster belonging to General domain, the cluster code is automatically build and linked but for other domains, the compiling and linking needs to be enabled. As Temperature Measurement belongs to Measurement and Sensing domain, enable the cluster code in Makefile: Router/Source/zcl_options.h This file is used to set the options used by the ZCL. Enable Clusters The cluster functionality for the router endpoint was enabled:   Enable any optional Attributes and Commands for the clusters  Add the cluster creation and initialization into ZigBee Base device definitions The cluster functionality for some of the clusters is already present on ZigBee Base Device. For Temperature Measurement cluster the functionality was added into ZigBee Base Device. <Path to JN-SW-4x70 SDK>/ Components/ZCL/Devices/ZHA/Generic/Include/base_device.h The first step was including the Temperature Measurement header files into base device header file as shown below:   The second step was adding cluster instance into base device Instance as shown below: The next step was to define the cluster into the base device structure as below: <Path to JN-SW-4x70 SDK>/ Components/ZCL/Devices/ZHA/Generic/Include/base_device.c The cluster create function for Temperature Measurement cluster for server was called in ZigBee base device registration function:   Router/Source/app_zcl_task.c Temperature Measurement Server Cluster Data Initialization - APP_vZCL_DeviceSpecific_Init() The default attribute values for the Temperature Measurement clusters are initialized:
查看全文
The High Power board design files can be found on the JN5189 product webpage, in the JN-RD-6054-JN5189 Design Files. More precisely, the reference manual and the design files are attached to this article (OM15072-2_MOD_EXT_AMP_QFN40_PCB2467-2.0.zip and JN-RM-2078-JN5189-Module-Development_1V4.pdf) Some guidance is available here. The RF performances are presented in the attached test report (powerpoint file). The FCC/IC Certificates or Declarations of conformity are in the article "Certificates/Declarations of conformity (nxp community)".  
查看全文
In this document we will be seeing how to create a BLE demo application for an adopted BLE profile based on another demo application with a different profile. In this demo, the Pulse Oximeter Profile will be implemented.  The PLX (Pulse Oximeter) Profile was adopted by the Bluetooth SIG on 14th of July 2015. You can download the adopted profile and services specifications on https://www.bluetooth.org/en-us/specification/adopted-specifications. The files that will be modified in this post are, app.c,  app_config.c, app_preinclude.h, gatt_db.h, pulse_oximeter_service.c and pulse_oximeter_interface.h. A profile can have many services, the specification for the PLX profile defines which services need to be instantiated. The following table shows the Sensor Service Requirements. Service Sensor Pulse Oximeter Service Mandatory Device Information Service Mandatory Current Time Service Optional Bond Management Service Optional Battery Service Optional Table 1. Sensor Service Requirements For this demo we will instantiate the PLX service, the Device Information Service and the Battery Service. Each service has a source file and an interface file, the device information and battery services are already implemented, so we will only need to create the pulse_oximeter_interface.h file and the pulse_oximeter_service.c file. The PLX Service also has some requirements, these can be seen in the PLX service specification. The characteristic requirements for this service are shown in the table below. Characteristic Name Requirement Mandatory Properties Security Permissions PLX Spot-check Measurement C1 Indicate None PLX Continuous Measurement C1 Notify None PLX Features Mandatory Read None Record Access Control Point C2 Indicate, Write None Table 2. Pulse Oximeter Service Characteristics C1: Mandatory to support at least one of these characteristics. C2: Mandatory if measurement storage is supported for Spot-check measurements. For this demo, all the characteristics will be supported. Create a folder for the pulse oximeter service in  \ConnSw\bluetooth\profiles named pulse_oximeter and create the pulse_oximeter_service.c file. Next, go to the interface folder in \ConnSw\bluetooth\profiles and create the pulse_oximeter_interface.h file. At this point these files will be blank, but as we advance in the document we will be adding the service implementation and the interface macros and declarations. Clonate a BLE project with the cloner tool. For this demo the heart rate sensor project was clonated. You can choose an RTOS between bare metal or FreeRTOS. You will need to change some workspace configuration.  In the bluetooth->profiles->interface group, remove the interface file for the heart rate service and add the interface file that we just created. Rename the group named heart_rate in the bluetooth->profiles group to pulse_oximeter and remove the heart rate service source file and add the pulse_oximeter_service.c source file. These changes will be saved on the actual workspace, so if you change your RTOS you need to reconfigure your workspace. To change the device name that will be advertised you have to change the advertising structure located in app_config.h. /* Scanning and Advertising Data */ static const uint8_t adData0[1] = { (gapAdTypeFlags_t)(gLeGeneralDiscoverableMode_c | gBrEdrNotSupported_c) }; static const uint8_t adData1[2] = { UuidArray(gBleSig_PulseOximeterService_d)}; static const gapAdStructure_t advScanStruct[] = { { .length = NumberOfElements(adData0) + 1, .adType = gAdFlags_c, .aData = (void *)adData0 }, { .length = NumberOfElements(adData1) + 1, .adType = gAdIncomplete16bitServiceList_c, .aData = (void *)adData1 }, { .adType = gAdShortenedLocalName_c, .length = 8, .aData = "FSL_PLX" } }; ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ We also need to change the address of the device so we do not have conflicts with another device with the same address. The definition for the address is located in app_preinclude.h and is called BD_ADDR. In the demo it was changed to: #define BD_ADDR 0xBE,0x00,0x00,0x9F,0x04,0x00 ‍‍‍ Add the definitions in ble_sig_defines.h located in Bluetooth->host->interface for the UUID’s of the PLX service and its characteristics. /*! Pulse Oximeter Service UUID */ #define gBleSig_PulseOximeterService_d 0x1822 /*! PLX Spot-Check Measurement Characteristic UUID */ #define gBleSig_PLXSpotCheckMeasurement_d 0x2A5E /*! PLX Continuous Measurement Characteristic UUID */ #define gBleSig_PLXContinuousMeasurement_d 0x2A5F /*! PLX Features Characteristic UUID */ #define gBleSig_PLXFeatures_d 0x2A60 ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ We need to create the GATT database for the pulse oximeter service. The requirements for the service can be found in the PLX Service specification. The database is created at compile time and is defined in the gatt_db.h.  Each characteristic can have certain properties such as read, write, notify, indicate, etc. We will modify the existing database according to our needs. The database for the pulse oximeter service should look something like this. PRIMARY_SERVICE(service_pulse_oximeter, gBleSig_PulseOximeterService_d) CHARACTERISTIC(char_plx_spotcheck_measurement, gBleSig_PLXSpotCheckMeasurement_d, (gGattCharPropIndicate_c)) VALUE_VARLEN(value_PLX_spotcheck_measurement, gBleSig_PLXSpotCheckMeasurement_d, (gPermissionNone_c), 19, 3, 0x00, 0x00, 0x00) CCCD(cccd_PLX_spotcheck_measurement) CHARACTERISTIC(char_plx_continuous_measurement, gBleSig_PLXContinuousMeasurement_d, (gGattCharPropNotify_c)) VALUE_VARLEN(value_PLX_continuous_measurement, gBleSig_PLXContinuousMeasurement_d, (gPermissionNone_c), 20, 3, 0x00, 0x00, 0x00) CCCD(cccd_PLX_continuous_measurement) CHARACTERISTIC(char_plx_features, gBleSig_PLXFeatures_d, (gGattCharPropRead_c)) VALUE_VARLEN(value_plx_features, gBleSig_PLXFeatures_d, (gPermissionFlagReadable_c), 7, 2, 0x00, 0x00) CHARACTERISTIC(char_RACP, gBleSig_RaCtrlPoint_d, (gGattCharPropIndicate_c | gGattCharPropWrite_c)) VALUE_VARLEN(value_RACP, gBleSig_RaCtrlPoint_d, (gPermissionFlagWritable_c), 4, 3, 0x00, 0x00, 0x00) CCCD(cccd_RACP) ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ For more information on how to create a GATT database you can check the BLE Application Developer’s Guide chapter 7. Now we need to make the interface file that contains all the macros and declarations of the structures needed by the PLX service. Enumerated types need to be created for each of the flags field or status field of every characteristic of the service. For example, the PLX Spot-check measurement field has a flags field, so we declare an enumerated type that will help us keep the program organized and well structured. The enum should look something like this: /*! Pulse Oximeter Service - PLX Spotcheck Measurement Flags */ typedef enum { gPlx_TimestampPresent_c = BIT0, /* C1 */ gPlx_SpotcheckMeasurementStatusPresent_c = BIT1, /* C2 */ gPlx_SpotcheckDeviceAndSensorStatusPresent_c = BIT2, /* C3 */ gPlx_SpotcheckPulseAmplitudeIndexPresent_c = BIT3, /* C4 */ gPlx_DeviceClockNotSet_c = BIT4 } plxSpotcheckMeasurementFlags_tag; ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ The characteristics that will be indicated or notified need to have a structure type that contains all the fields that need to be transmitted to the client. Some characteristics will not always notify or indicate the same fields, this varies depending on the flags field and the requirements for each field. In order to notify a characteristic we need to check the flags in the measurement structure to know which fields need to be transmitted. The structure for the PLX Spot-check measurement should look something like this: /*! Pulse Oximeter Service - Spotcheck Measurement */ typedef struct plxSpotcheckMeasurement_tag { ctsDateTime_t timestamp; /* C1 */ plxSpO2PR_t SpO2PRSpotcheck; /* M */ uint32_t deviceAndSensorStatus; /* C3 */ uint16_t measurementStatus; /* C2 */ ieee11073_16BitFloat_t pulseAmplitudeIndex; /* C4 */ uint8_t flags; /* M */ }plxSpotcheckMeasurement_t; ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ The service has a configuration structure that contains the service handle, the initial features of the PLX Features characteristic and a pointer to an allocated space in memory to store spot-check measurements. The interface will also declare some functions such as Start, Stop, Subscribe, Unsubscribe, Record Measurements and the control point handler. /*! Pulse Oximeter Service - Configuration */ typedef struct plxConfig_tag { uint16_t serviceHandle; plxFeatures_t plxFeatureFlags; plxUserData_t *pUserData; bool_t procInProgress; } plxConfig_t; ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ The service source file implements the service specific functionality. For example, in the PLX service, there are functions to record the different types of measurements, store a spot-check measurement in the database, execute a procedure for the RACP characteristic, validate a RACP procedure, etc. It implements the functions declared in the interface and some static functions that are needed to perform service specific tasks. To initialize the service you use the start function. This function initializes some characteristic values. In the PLX profile, the Features characteristic is initialized and a timer is allocated to indicate the spot-check measurements periodically when the Report Stored Records procedure is written to the RACP characteristic. The subscribe and unsubscribe functions are used to update the device identification when a device is connected to the server or disconnected. bleResult_t Plx_Start (plxConfig_t *pServiceConfig) { mReportTimerId = TMR_AllocateTimer(); return Plx_SetPLXFeatures(pServiceConfig->serviceHandle, pServiceConfig->plxFeatureFlags); } ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ All of the services implementations follow a similar template, each service can have certain characteristics that need to implement its own custom functions. In the case of the PLX service, the Record Access Control Point characteristic will need many functions to provide the full functionality of this characteristic. It needs a control point handler, a function for each of the possible procedures, a function to validate the procedures, etc. When the application makes a measurement it must fill the corresponding structure and call a function that will write the attribute in the database with the correct fields and then send an indication or notification. This function is called RecordMeasurement and is similar between the majority of the services. It receives the measurement structure and depending on the flags of the measurement, it writes the attribute in the GATT database in the correct format. One way to update a characteristic is to create an array of the maximum length of the characteristic and check which fields need to be added and keep an index to know how many bytes will be written to the characteristic by using the function GattDb_WriteAttribute(handle, index, &charValue[0]). The following function shows an example of how a characteristic can be updated. In the demo the function contains more fields, but the logic is the same. static bleResult_t Plx_UpdatePLXContinuousMeasurementCharacteristic ( uint16_t handle, plxContinuousMeasurement_t *pMeasurement ) { uint8_t charValue[20]; uint8_t index = 0; /* Add flags */ charValue[0] = pMeasurement->flags; index++; /* Add SpO2PR-Normal */ FLib_MemCpy(&charValue[index], &pMeasurement->SpO2PRNormal, sizeof(plxSpO2PR_t)); index += sizeof(plxSpO2PR_t); /* Add SpO2PR-Fast */ if (pMeasurement->flags & gPlx_SpO2PRFastPresent_c) { FLib_MemCpy(&charValue[index], &pMeasurement->SpO2PRFast, sizeof(plxSpO2PR_t)); index += sizeof(plxSpO2PR_t); } return GattDb_WriteAttribute(handle, index, &charValue[0]); } ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ The app.c handles the application specific functionality. In the PLX demo it handles the timer callback to make a PLX continuous measurement every second. It handles the key presses and makes a spot-check measurement each time the SW3 pushbutton is pressed. The GATT server callback receives an event when an attribute is written, and in our application the RACP characteristic is the only one that can be written by the client. When this event occurs, we call the Control Point Handler function. This function makes sure the indications are properly configured and check if another procedure is in progress. Then it calls the Send Procedure Response function, this function validates the procedure and calls the Execute Procedure function. This function will call one of the 4 possible procedures. It can call Report Stored Records, Report Number of Stored Records, Abort Operation or Delete Stored Records. When the project is running, the 4 LEDs will blink indicating an idle state. To start advertising, press the SW4 button and the LED1 will start flashing. When the device has connected to a client the LED1 will stop flashing and turn on. To disconnect the device, hold the SW4 button for some seconds. The device will return to an advertising state. In this demo, the spot-check measurement is made when the SW3 is pressed, and the continuous measurement is made every second. The spot-check measurement can be stored by the application if the Measurement Storage for spot-check measurements is supported (bit 2 of Supported Features Field in the PLX Features characteristic). The RACP characteristic lets the client control the database of the spot-check measurements, you can request the existing records, delete them, request the number of stored records or abort a procedure. To test the demo you can download and install a BLE Scanner application to your smartphone that supports BLE. Whit this app you should be able to discover the services in the sensor and interact with each characteristic. Depending on the app that you installed, it will parse known characteristics, but because the PLX profile is relatively new, these characteristics will not be parsed and the values will be displayed in a raw format. In Figure 1, the USB-KW40Z was used with the sniffer application to analyze the data exchange between the PLX sensor and the client. You can see how the sensor sends the measurements, and how the client interacts with the RACP characteristic. Figure 1. Sniffer log from USB-KW40Z
查看全文
KW45’s three-core architecture integrates a 96 MHz CM33 application core, dedicated CM3 radio core and an isolated EdgeLock Secure Enclave. The Flash-based radio core with dedicated SRAM delivers a highly configurable and upgradeable software-implemented radio, freeing resources on the main core for customer application space. The Bluetooth Low Energy 5.3-compliant radio supports up to 24 simultaneous secure connections. The EdgeLock Secure Enclave’s isolated execution environment provides a set of cryptographic accelerators, key store operations and secure lifecycle management that minimizes main core security responsibilities. The KW45 MCU additionally integrates FlexCAN, helping enable seamless integration into an automobile’s in-vehicle or industrial CAN communication network. The FlexCAN module can support CAN’s flexible data rate (CAN FD) for increased bandwidth and lower latency. KW45 Block Diagram KW45 Architecture Block Diagram Documents Reference Manual Datasheet Errata Secure Reference manual** Certifications SESIP Cert SESIP ST PSA Certification RED Certification EUROPEAN UNION DECLARATION OF CONFORMITY (EVK) EUROPEAN UNION DECLARATION OF CONFORMITY (LOC) Japan MIC KW45-LOC _TELEC-20250221 see attached below Bluetooth Specifications Bluetooth_5.0_Feature_Overview  Bluetooth_5.1_Feature_Overview  Bluetooth_5.2_Feature_Overview Bluetooth_5.3_Feature_Overview Bluetooth_5.4_Feature_Overview Bluetooth_6_Feature_Overview Bluetooth_6.1_Feature_Overview Bluetooth_6.2_Feature_Overview Evaluation boards KW45 KW45-EVK KW45-EVK Schematic KW45-EVK Design Files KW45-EVK User manual KW45-LOC User manual KW45-EVK Getting Started Application Notes Software, Hardware and Peripherals: AN14122 : How to use RTC on KW45 This application note describes how to configure and use the RTC peripheral in a BLE demo AN14141 : Enabling Watchdog Timer Module on KW45 Bluetooth Low Energy Connectivity Stack This application note describes the process to implement the WDOG timer in a Connectivity Stack demo. AN13855 : KW45/K32W1 Integrating the OTAP Client Service into a Bluetooth LE Peripheral Device This Application note provides the steps and process for integrating the Over the Air Programming Client Service into a BLE peripheral device. AN13584 : Kinetis KW45 and K32W1 Loadpull Report This application note describes measurement methodology and associated results on the load-pull characteristics. AN13860 : Creating Firmware Update Image for KW45/K32W1 using OTAP tool This application note provides the steps to create and upgrade the image on the KW45 board via OTAP. AN14077 : Steps to migrating KW45 (1MB) to KW45 (512kB) This application note describes the initial steps require to migrate from 1MB flash to 512kB flash. AN14746 : EEPROM Emulation for the KW45B41Z and K32W148 This document describes the process for the EEPROM emulation for the KW45B41Z and K32W148. Power Management: AN13230: Kinetis KW45 and K32W1 Bluetooth LE Power Consumption Analysis This application note provides information about the power consumption of KW45 wireless MCUs, the hardware design and optimized for low power operation. AN13831: KW45/K32W1 Power Management Hardware This application note describes the usage of the different modules dedicated to power management in the KW45/K32W1 MCU. RF: AN13687 : K32W1 Connectivity test for 802.15.4 Application This application note describes how to use the connectivity test tool to perform K32W1 802.15.4 RF performance. AN13728 : KW45 RF System Evaluation Report for Bluetooth LE and IEEE 802.15.4 Applications This application note provides the radio frequency evaluation test results of the KW45 board for BLE (2FSK modulation) and for IEEE 802.15.4 (OQPSK modulation) applications. Also describes the setup and tools that can be used to perform the tests.  AN14098: KW45-LOC RF Test Report This application note provides basic RF test result of the KW45B41Z localization board.  AN13228 : KW45-EVK RF System Evaluation Report for BLE Applications This application note provides the RF evaluation test result of the KW45B41Z-EVK for BLE application using two frequency Shift Keying modulation. AN13229 : KW45-EVK Co-existence with RF System Evaluation Report for BLE application This application note provides the RF evaluation test results of the KW45B41Z-EVK for BLE application (2FSK modulation) AN13512 : Kinetis Wireless Family Products BLE Coexistence with Wi-Fi Application This application note provides the K32W1/4X low energy family products immunity on Wi-Fi signals and methods to improve coexistence with Wi-Fi  AN14294 : Out of Band Implementation with KW45 This document explains the steps required to set up an Out of Band (OOB) pairing connection between two KW45 EVK boards, using UART and CAN communication interfaces to share OOB data. Security: AN13859 : KW45/K32W1 In-System Programming Utility This application note provides steps to boot KW45/K32W1 MCU in ISP mode and establish various serial connections to communicate with the MCU. AN14003 : Programming the KW45 Flash for Application and Radio Firmware via Serial Wire Debug during mass production This application note describes the steps to write, burn and programming all the necessary settings via SWD in mass production.  AN13883 : Updating KW45 Radio Firmware Via ISP Using SPSDK This application note provides steps to boot KW45/K32W1 MCU in ISP mode and update the radio firmware with secure binary. AN14109 : KW45 and K32W148 Secure  Boot Using the SEC Tool This application note provides steps to do secure boot KW45/K32W1 MCU using signed images and secure binaries on the SEC GUI tool. AN13838 :  KW45 and K32W148 Secure  Boot Using the SPSDK Command line Tool This application note provides steps to do secure boot KW45/K32W1 MCU using signed images and secure binaries on the SPSDK command line tool. AN13931 : Managing Lifecycles on KW45 and K32W148 This application note provides steps to do transition lifecycles KW45/K32W1 MCU using the SEC GUI and SPSDK command line tools.  AN14158: Debug Authentication on KW45/ K32W148 This application note describes how to do debug authentication to securely debug an application in the field.  AN14544 : EdgeLock 2GO Services for MPU and MCU This application note introduces the EL2GO services for NXP devices. This allows trust provisioning of the device in an untrusted environment.  AN14174: KW45/K32W1 Flash Encryption using NPXThis application note provides steps to do enable on-the-fly encryption on KW45/K32W1 MCU. AN14158: debug authentication on KW45/K32W148 This application note describes the steps for debug authentication using the Secure Provisioning SDK tool (SPSDK). Support If you have questions regarding KW45, please leave your question in our Wireless MCU Community! here   Useful Links   [MCUXSDK] How to use GitHub SDK for KW4x, MCXW7x, MCXW2x - NXP Community this community post provides step by step how to use GitHub SDK [MCUXSDK] GitHub SDK - Documentation for Bluetooth LE platforms - NXP Community this community post provides the documentation for BLE platforms.  Clock Measuring using the Signal Frequency Analyzer (SFA) module for KW45/KW47/MCXW71/MCXW72 - NXP Community : this community provides the steps on how to use the Signal Frequency Analyzer  The best way to build a PCB first time right with KW45 (Automotive) or K32W1/MCXW71 (IoT/Industrial)... Community : In this community provides the important link to build a PCB using a KW45 or K32W148 and MCXW71 and all concerning the radio performances, low power and radio certification (CE/FCC/ICC) How to use the HCI_bb on Kinetis family products and get access to the DTM mode:  This article is presenting two parts: How to flash the HCI_bb binary into the Kinetis product. Perform RF measurement using the R&S CMW270 BLE HCI Application to set transmitter/receiver test commands: This article provides the steps to show how user could send serial commands to the device. Bluetooth LE HCI Black Box Quick Start Guide : This article describes a simple process for enabling the user controls the radio through serial commands. Kinetis (K32/38/KW45 & K32W1/MCXW71) Power Profile Tools:  This page is dedicated to the Kinetis (KW35/KW38/KW45) and MCX W7x (MCX W71) Power Profile Tools. It will help you to estimate the power consumption in your application (Automotive or IoT) and evaluate the battery lifetime of your solution. KW45/K32W1 32MHz & 32kHz Oscillation margins: this article provides the properly configuration for the Oscillation margins for the circuit. KW45/MCXW71 Changing Clocking peripherals from FRO6M to other clock sources:  This article provides a comprehensive guide to selecting and configuring alternative clock sources   Reference Designs Bluetooth Ranging Access Vehicle Enablement System - NXP Community Blue Ravens (Bluetooth Ranging Access Vehicle Enablement System) is a system solution developed by NXP to assist customers in designing their own BLE-based car access solutions using NXP products.   Demo (video) KW45 Based CS 1 to Many Demo NXP - Channel Sounding   Training BLE Introduction  RF Switch Comparison Absorptive/Reflective Standards Comparison ETSI / FCC / ARIB requirements BLE Channel Sounding  - Overview BLE Channel Sounding - RF Hardware BLE Channel Sounding - ANSYS Modeling Tools  BLE Channel Sounding - Antenna Prototypes Validation Measurements     Equipment Wireless Equipment: This article provides the links to the Equipment that helps to the project development  Development Tools  SDK builder: The MCUXpresso SDK brings open-source drivers, middleware, and reference example application to speed your software development. SDK GitHub: SDK open-source Drivers, middleware and reference examples in Github NXP MCUXpresso: MCUXpresso IDE offers advanced editing, compiling and debugging features with the addition of MCU-Specific debugging. Supports connections with all general-purpose Arm Cortex-M.  NXP SPSDK: Is a unified, reliable, and easy to use Python SDK library working across the NXP MCU portfolio providing a strong foundation from quick customer prototyping up to production deployment. NXP SEC Tool: The MCUXpresso Secure Provisioning Tool us a GUI-based application provided to simplify generation and provisioning of bootable executables on NCP MCU devices. NXP OTAP Tool: Is an application that helps the user to perform an over the air firmware update of an NXP development board. Config Tool: MCUXpresso Config Tools, an integrated suite of configuration tools, these configuration tools allow developers to quickly build a custom SDK and leverage pins, clocks and peripheral to generate initialization C code or register values for custom board support. SDK Examples for Wireless MCUs: The wireless examples feature many common Bluetooth configurations. **For secure files is necessary to request additional access. 
查看全文
Bluetooth® Low-Energy (BLE) RF PHY tests can be done by using the Direct Test Mode (DTM).  This document will help as a guide to perform the test using a device from the KW family.     Direct Test Mode Direct Test Mode (DTM) is used to control the Device Under Test (DUT) and provides a report with the results from the tests performed by the Tester.   There are two ways to perform those tests:   HCI Through a 2-wire UART interface   The packet format from the DTM is different from the HCI commands.   For further information of the commands and this type of tests, please refer to the Bluetooth Core Specifications, Vol 6, Part F: Direct Test Mode   Software This guide will use the KW41Z as example, but the same changes must be applicable for the rest of the devices Download and install the software SDK of the device to use by following the getting started in the device page. In this case the SDK of the KW41Z will be downloaded from the MCUXpresso Builder. Setup for DTM using HCI Import the hci_black_box example to the IDE according to the getting started of the device.   Download and open the latest version of the Test Tool available in the page of the device under Lab & Test Software in the Software and Tools Tab. Open the Command console of the board, please be sure that you have the correct baud rate set for the example (Default: 115200) Select one of the available commands to either start or finish tests    Setup for DTM using DTM pins You can choose from any example available while making sure that the pins chosen for DTM  are not occupied or used. Import the beacon example to the IDE according to the getting started of the device.   The DTM pins behave as a UART interface; in order to enable them in our KW devices there is the need to follow the next steps Look at the Reference manual of the device and locate the pins that support the DTM_TX and the DTM_RX. In this case, we will select the PTB1 and PTB2.  Set the ALT_MUX of the pin in the code to work as DTM   PORT_SetPinMux(PORTB, PIN1_IDX, kPORT_MuxAlt2);            /* PORTB1 (pin 17) is configured as DTM_RX */   PORT_SetPinMux(PORTB, PIN2_IDX, kPORT_MuxAlt3);            /* PORTB2 (pin 18) is configured as DTM_TX */‍‍‍‍‍‍‍‍‍‍ Configure the baud rate of the DTM pins, this can be achieved by writing to the DTM_2WIRE_CONFIG register. This register is not available in the header file by default, so there is the need to create a pointer to such address. To verify this data, you can check the chapter 45.2.3.1.4 Test and Debug Registers Descriptions for the Bluetooth Link Layer of the reference manual. #define DTM_2WIRE_CONFIG                0x580 #define BTLE_RF_DTM_2WIRE_CONFIG        (*(volatile uint16_t *) (BTLE_RF_BASE+DTM_2WIRE_CONFIG)) BTLE_RF_DTM_2WIRE_CONFIG = 0x0042;  /*Configure DTM pins baud rate of 115200*/‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
查看全文
Please find here all the information needed to build your own PCB based on K32W061/041(AM/A), QN9090/9030(T) or JN5189/5188(T). Your first task before to send any inquiry to NXP support is to fill the K32W Design In CHECK LIST available in this ticket.   K32W061 Manufacturing package  Find here all the product pages, most of the HW documents are in the corresponding platforms web pages: K32W061/041 (AM/A) QN9090/9030(T) JN5189/5188(T)   The K32W EVK getting started webpage: IOT_ZTB-DK006 Get started page (nxp.com) IoT_ZTB getting started manual (nxp.com)   HW: HW design consideration : JN-RM-2078-JN5189-Module-Development_1V4.pdf (see attached file) JN-RM-2079-QN9090-Module-Development_1V0.pdf (see attached file) JN-RM-2080-K32W-Module-Development_1V0.pdf (see attached file)   Radio: RF report:  JN5189: https://www.nxp.com/docs/en/application-note/AN12154.pdf (nxp.com) QN9090: https://www.nxp.com/docs/en/nxp/application-notes/AN12610.pdf (nxp.com) K32W: https://www.nxp.com/docs/en/application-note/AN12798.pdf (nxp.com) Antenna: https://www.nxp.com/docs/en/application-note/AN2731.pdf (nxp.com)   Low Power Consumption:  JN5189: https://www.nxp.com/docs/en/application-note/AN12898.pdf (nxp.com) QN9090: https://www.nxp.com/docs/en/application-note/AN12902.pdf (nxp.com) K32W: https://www.nxp.com/docs/en/application-note/AN12846.pdf (nxp.com) A power calculator tool is available here: https://community.nxp.com/t5/Connectivity-Support-QN-JN-KW/QN9090-Bluetooth-LE-Power-Profile-Calculator-Tool/ta-p/1209602 SW tools: Customer Module Evaluation Tool  (nxp.com) Bluetooth Low Energy Certification Tool (nxp.com) K32W041/K32W061/QN9090(T)/QN9030(T) Bluetooth Low Energy Certification Tool User's Guide (nxp.com)     Certification: Certificates/Declarations of conformity (nxp community)  
查看全文
I was investigating about how to create a current profile and I found interesting information I would like to share with the community. So, I decided to create an example to accomplish this task using BLE stack included in the MKW40Z Connectivity Software package. The demo to create is an Humidity Collector which make use of the Humidity custom profile and is based on the Temperature Collector demonstration application. The first thing to know is that the Generic Attribute Profile (GATT) establishes in detail how to exchange all profile and user data over a BLE connection. GATT deals only with actual data transfer procedures and formats. All standard BLE profiles are based on GATT and must comply with it to operate correctly. This makes GATT a key section of the BLE specification, because every single item of data relevant to applications and users must be formatted, packed, and sent according to the rules.                                      GATT defines two roles: Server and Client. The GATT server stores the data transported over the Attribute Protocol (ATT) and accepts Attribute Protocol requests, commands and confirmations from the GATT client. The GATT client accesses data on the remote GATT server via read, write, notify, or indicate operations. Notify and indicate operations are enabled by the client but initiated by the server, providing a way to push data to the client. Notifications are unacknowledged, while indications are acknowledged. Notifications are therefore faster, but less reliable. Figure 1. GATT Client-Server      GATT Database establishes a hierarchy to organize attributes. These are the Profile, Service, Characteristic and Descriptor. Profiles are high level definitions that define how services can be used to enable an application and Services are collections of characteristics. Descriptors defined attributes that describe a characteristic value. To define a GATT Database several macros are provided by the GATT_DB API in the Freescale BLE Stack, which is part KW40Z Connectivity Software package. Figure 2. GATT database      To know if the Profile or service is already defined in the specification, you have to look for in Bluetooth SIG profiles and check in the ble_sig_defines.h file if this is already declared in the code. In our case, the service is not declared, but the characteristic of the humidity is declared in the specification. Then, we need to check if the characteristic is already included in ble_sig_defines.h. Since, the characteristic is not included, we need to define it as shown next: /*! Humidity Charactristic UUID */ #define gBleSig_Humidity_d                      0x2A6F      The Humidity Collector is going to have the GATT client; this is the device that will receive all information from  the GATT server. Demo provided in this post works like the Temperature Collector. When the Collector enables the notifications from the sensor, received notifications will be printed in the serial terminal. In order to create the demo we need to define or develop a service that has to be the same as in the GATT Server, this is declared in the gatt_uuid128.h.If the new service is not the same, they will never be able to communicate each other. All macros function or structures in BLE stack of KW40Z Connectivity Software have a common template. Hence, we need to define this service in the gatt_uuid128.h as shown next: /* Humidity */ UUID128(uuid_service_humidity, 0xfe ,0x34 ,0x9b ,0x5f ,0x80 ,0x00 ,0x00 ,0x80 ,0x00 ,0x10 ,0x00 ,0x02 ,0x00 ,0xfa ,0x10 ,0x10)      During the scanning process is when the client is going to connect with the Server. Hence, function CheckScanEvent can help us to ensure that peer device or server device support the specified service, in this case, it will be the humidity service we just created in the previous step. Then, CheckScanEvent needs to check which device is on advertising mode and with MatchDataInAdvElementList to verify if it is the same uuid_service_humidity, if the service is not in the list, client is not going to connect. CheckScanEvent function should look as shown next: static bool_t CheckScanEvent(gapScannedDevice_t* pData) { uint8_t index = 0; uint8_t name[10]; uint8_t nameLength; bool_t foundMatch = FALSE; while (index < pData->dataLength) {         gapAdStructure_t adElement;                 adElement.length = pData->data[index];         adElement.adType = (gapAdType_t)pData->data[index + 1];         adElement.aData = &pData->data[index + 2];          /* Search for Humidity Custom Service */         if ((adElement.adType == gAdIncomplete128bitServiceList_c) ||           (adElement.adType == gAdComplete128bitServiceList_c))         {             foundMatch = MatchDataInAdvElementList(&adElement, &uuid_service_humidity, 16);         }                 if ((adElement.adType == gAdShortenedLocalName_c) ||           (adElement.adType == gAdCompleteLocalName_c))         {             nameLength = MIN(adElement.length, 10);             FLib_MemCpy(name, adElement.aData, nameLength);         }                 /* Move on to the next AD elemnt type */         index += adElement.length + sizeof(uint8_t); } if (foundMatch) {         /* UI */         shell_write("\r\nFound device: \r\n");         shell_writeN((char*)name, nameLength-1);         SHELL_NEWLINE();         shell_writeHex(pData->aAddress, 6); } return foundMatch; } The humidity_interface.h file should define the client structure and the server structure. For this demo, we only need the client structure, however, both are defined for reference. The Client Structure has all the data of the Humidity Service, in this case is a Service, characteristic, descriptor and CCCD handle and the format of the value. /*! Humidity Client - Configuration */ typedef struct humcConfig_tag { uint16_t    hService; uint16_t    hHumidity; uint16_t    hHumCccd; uint16_t    hHumDesc; gattDbCharPresFormat_t  humFormat; } humcConfig_t; The next configuration structure is for the Server; in this case we don’t need it. /*! Humidity Service - Configuration */ typedef struct humsConfig_tag { uint16_t    serviceHandle; int16_t     initialHumidity;        } humsConfig_t;     Now that the Client Structure is declared, go to the app.c and modify some functions. There are functions that help to store all the data of the humidity service. In our case they are 3 functions for the service, characteristic and descriptor. You have to be sure that the service that you create and the characteristics of humidity are in the functions. The Handle of each data is stored in the structure of the client. The three functions that need to be modify are the next: BleApp_StoreServiceHandles() stores handles for the specified service and characteristic. static void BleApp_StoreServiceHandles (     gattService_t   *pService ) {     uint8_t i;           if ((pService->uuidType == gBleUuidType128_c) &&         FLib_MemCmp(pService->uuid.uuid128, uuid_service_humidity, 16))     {         /* Found Humidity Service */         mPeerInformation.customInfo.humClientConfig.hService = pService->startHandle;                 for (i = 0; i < pService->cNumCharacteristics; i++)         {             if ((pService->aCharacteristics[i].value.uuidType == gBleUuidType16_c) &&                 (pService->aCharacteristics[i].value.uuid.uuid16 == gBleSig_Humidity_d))             {                 /* Found Humidity Char */                 mPeerInformation.customInfo.humClientConfig.hHumidity = pService->aCharacteristics[i].value.handle;             }         }     } } BleApp_StoreCharHandles() handles the descriptors. static void BleApp_StoreCharHandles (     gattCharacteristic_t   *pChar ) {     uint8_t i;         if ((pChar->value.uuidType == gBleUuidType16_c) &&         (pChar->value.uuid.uuid16 == gBleSig_Humidity_d))     {            for (i = 0; i < pChar->cNumDescriptors; i++)         {             if (pChar->aDescriptors[i].uuidType == gBleUuidType16_c)             {                 switch (pChar->aDescriptors[i].uuid.uuid16)                 {                     case gBleSig_CharPresFormatDescriptor_d:                     {                         mPeerInformation.customInfo.humClientConfig.hHumDesc = pChar->aDescriptors[i].handle;                         break;                     }                     case gBleSig_CCCD_d:                     {                         mPeerInformation.customInfo.humClientConfig.hHumCccd = pChar->aDescriptors[i].handle;                         break;                     }                     default:                         break;                 }             }         }     } } BleApp_StoreDescValues() stores the format of the value. static void BleApp_StoreDescValues (     gattAttribute_t     *pDesc ) {     if (pDesc->handle == mPeerInformation.customInfo.humClientConfig.hHumDesc)     {         /* Store Humidity format*/         FLib_MemCpy(&mPeerInformation.customInfo.humClientConfig.humFormat,                     pDesc->paValue,                     pDesc->valueLength);     }   }      After we store all the data of the Humidity Service, we need to check the notification callback. Every time the Client receives a notification with the BleApp_GattNotificationCallback(),  call the BleApp_PrintHumidity() function and check the Format Value; in this case is 0x27AD  that mean percentage and also have to be the same on the GATT server. static void BleApp_GattNotificationCallback (     deviceId_t serverDeviceId,     uint16_t characteristicValueHandle,     uint8_t* aValue,     uint16_t valueLength ) { /*Compare if the characteristics handle Server is the same of the GATT Server*/     if (characteristicValueHandle == mPeerInformation.customInfo.humClientConfig.hHumidity)     {            BleApp_PrintTemperature(*(uint16_t*)aValue);     }  } BleApp_PrintHumidity() print the value of the Humidity, but first check if the format value is the same. static void BleApp_PrintHumidity (     uint16_t humidity ) {     shell_write("Humidity: ");     shell_writeDec(humidity);      /*If the format value is the same, print the value*/     if (mPeerInformation.customInfo.humClientConfig.humFormat.unitUuid16 == 0x27AD)     {         shell_write(" %\r\n");     }     else     {         shell_write("\r\n");     } } Step to include the file to the demo. 1. Create a clone of the Temperature_Collector with the name of Humidity_Collector 2. Unzip the Humidity_Collector.zip file attached to this post. 3. Save the humidity folder in the fallowing path: <kw40zConnSoft_install_dir>\ConnSw\bluetooth\profiles . 4. Replaces the common folder in the next path: <kw40zConnSoft_install_dir>\ConnSw\examples\bluetooth\humidity_sensor\common . Once you already save the folders in the corresponding path you must to indicate in the demo where they are and drag the file in the humidity folder to the workspace. For test the demo fallow the next steps: Compile the project and run. Press SW1 for the advertising/scanning mode, and wait to connect it. Once the connection finish, press the SW1 of the Humidity Sensor board to get and print the data. Enjoy the demo! NOTE: This demo works with the Humidity Sensor demo. This means that you need one board programmed with the Humidity Sensor application and a second board with the Humidity Collector explained in this post. Figure 3. Example of the Humidity Collector using the Humidity Sensor.
查看全文
This document describes how to sniff ZigBee packets to identify messages and layers from the ZigBee stack using the MC1322x USB dongle and Wireshark protocol analyzer. --------------------------------------------------------------------------------------------------------- Pre-Requisites If not done yet, download & Install Wireshark protocol analyzer http://www.wireshark.org/download.html Download the Wireshark ZigBee Utility Zip file from Sourceforge http://sourceforge.net/projects/wiresharkzigbee/ Unzip the file in a known location -------------------------------------------------------------------------------------------------------- 1. Install MC1322x dongle Plug-in MC1322xUSB dongle and wait for Windows to install the driver. If the driver was not found, steer Windows manually to the directory         C:\Program Files\Freescale\Drivers If BeeKit is not installed, be aware of the following: The 1322x USB Dongle uses the FTDI serial to USB converter, Virtual COM Port (VCP) driver for Windows, available at www.ftdichip.com/ftdrivers.htm. The FTDI web site offers drivers for other platforms including Windows® (98 through Vista x64 and CE), MAC OS (8 through X) and Linux. Download the appropriate driver and follow the instructions to complete driver installation. 2. Check COM port Once installed, the MC1322xUSB dongle should be listed in the available COM ports in Widows device manager. Verify the board’s drivers were successfully installed and take note of the COM port assigned      3. Run the ZigBee Utility Open a command console and navigate to the directory where Wireshark Zigbee utility files were unzipped. c:\<path> Then start the .exe utility and set the serial port and ZigBee channel to monitor, for instance:     4. Setting Wireshark Start Wireshark and open Capture>Options Dialog Click on “Manage Interfaces” and add a new pipe with ‘\\.\pipe\wireshark’. Save it and start capture. 5. Start sniffing
查看全文
This guide will show a way to set up and enable an I2C Serial Interface to send a string of data instances using one of the Wireless Bluetooth SDK examples and the Serial Manager API.
查看全文
As know, FSK and OOK are the modulation types that can be configured in the radio by setting the bits 4-3 from the RegDataModul register, as shown in below picture taken from Reference Manual:                                                          A common inquire you could have is: what modulation should I use? Let's first understand how these modulations work. FSK: Frequency Shift Keying is a modulation type that uses two frequencies, for 0 and 1. In a spectrum analyzer we can see a spectrum similar to the next picture, where the frequency for 0's is separated from the central frequency with FDev, and same case for the frequency for the 1's: OOK: On Off Keying is a modulation type that represents a logic 1 with the presence of the carrier frequency and a logic 0 with the absence of it. In a spectrum analyzer we can see a spectrum similar to the next picture, where the central frequency represents a logic 1. We can not see a logic 0 in the spectrum due to it's represented as the absence of power. Then what modulation should I use? FSK is most commonly used because is more spectral efficient so has better sensitivity. In the other hand, OOK modulation is commonly used in applications where the frequency accuracy can not be guaranteed. It also helps in conserving battery power due to the power absence for the logic 0's. Regards, Luis Burgos.
查看全文
802.15.4 wireless sniffers like the USB-KW41Z are capable of capturing over-the-air traffic. The captured packets are passed to a network protocol decoder like Wireshark over a network interface tunnel built by the Kinetis Protocol Analyzer.   Hardware  One USB-KW41Z preloaded with sniffer firmware ( instructions found at www.nxp.com/usb-kw41z )  Software Download & Install Thread Wireshark from wireshark.org which is an open-source network protocol analyzer capable of debugging over the air communication between Thread devices. Kinetis Protocol Analyzer is a software that provides a bridge between the USB-KW41 and Wireshark.  Wireshark Configuration  Open Wireshark from the Program Files Click Edit and select Preferences  Click Protocols to expand a list of protocols Select IEEE 802.15.4, click the Decryption Keys Edit... button Create a new key entry by pressing the plus button, then set the following values and click OK       Decryption key = 00112233445566778899aabbccddeeff      Decryption key index = 1      Key hash = Thread hash Find CoAP and configure it with CoAP UDP port number = 5683 Click Thread and select Decode CoAP for Thread  with Thread sequence counter = 00000000 as shown below At the 6LoWPAN preferences, add the Context 0 value of fd00:0db8::/64 Click OK and close Wireshark Configure Kinetis Protocol Analyzer  Connect the USB-KW41Z to one of the USB ports on your computer Open the device manager and look for the device connected port Open the "Kinetis Protocol Analyzer Adapter" program Make sure, you have a USB-KW41Z connected to your PC when opening the program because the Kinetis Protocol Adapter will start looking for kinetis sniffer hardware. Once the USB-KW41Z is detected, the previously identify COM port will be displayed Select the desired IEEE 802.15.4 channel to scan in the Kinetis Protocol Analyzer window. This guide selects channel 12 as an example  Click on the Wireshark icon to open Wireshark Network Protocol Analyzer An error may appear while opening Wireshark, click OK and continue Wireshark Sniffing Wireshark Network Analyzer will be opened. On the "Capture" option of the main window, select the Local Area Connection that was created by the Kinetis Protocol Analyzer, in this example, Kinetis Protocol Analyzer created "Local Area Connection 2", then click "Start" button. USB-KW41Z will start to sniff and upcoming data will be displayed in the "Capture" window of the Wireshark Network Protocol Analyzer.
查看全文
The “BeyondStudio for NXP” Integrated Development Environment (IDE) provides a platform for the development of wireless network applications to be run on NXP’s JN516x family of wireless microcontrollers. For more details and installation guide.  JN-UG-3098 (BeyondStudio for NXP Installation and User Guide). This document explains the common issues that the user will face when trying to develop a new application using BeyondStudio IDE.   First of all, be sure that you are working with the latest SDK version and application note.    Import Problems After you import some application note that you want to take as reference. 2.2 Importing a Project. BeyondStudio for NXP Installation and User Guide.     1. Wrong Path A  common issue is a user uses another path for the installation of the SDK than the default one (C:\nxp\bstudio_nxp\workspace). When trying to find the Makefile ("SDK/JN-SW-4168/Stack/Common/Build/config.mk"), the IDE uses a relative path, for that reason it assumes that the file is in the correct directory. As the path was changed, the file can’t be found.   2.Project Directory After you select the Application Note (AN) you want to import remember that there will be an option for the JN517x as most of the projects are compatible between them (Zigbee 3.0, ZigBee Link Light). Nonetheless, BeyondStudio is not compatible with the JN517x.  While importing the project you only must select the JN516x project and none of the options must not be selected.     Linking Errors Open a source file (.c) or a header file (.h),  you will notice that the IDE shows a lot of errors even though the project has not been compiled yet. The errors you are seeing is Eclipse not being able to resolve various variables and functions within the SDK. You might see some errors like: Symbol “xxx” could not be resolved for example. After starting the compilation process, look at the console log and notice that the bin file is being generated correctly. Do not try to add another file in the path and Symbols trying to avoid all those errors; the IDE will look for the includes that the project needs. If you used the default path location, it will not have any problem with the compilation. The OS_Gen, ZPS_Gen, and PDUM_Gen, for example, are all files automatically generated based on the configuration files, performing a clean will remove those files but will be created again after a new compilation. File app.zpscfg Problems Encountered The next error will appear if the Zigbee Plug-in is not installed. Follow the installation procedure for the plug-ins 1.2.3 Installing the ZigBee Plug-ins BeyondStudio for NXP Installation and User Guide. Look at the installation folder that is included in the SDK. C:\NXP\bstudio_nxp\sdk\JN-SW-41xx\Tools\Eclipse_plugins\com.nxp.sdk.update_site For a better reference the ZPS Configuration Editor provides a convenient way to set ZigBee network parameters ZigBee PRO Stack User Guide I hope it helps. Regards, Mario
查看全文
Introduction When a Bluetooth LE Central and Peripheral devices are in connection, data within the payload can be encrypted. Encryption of the channel can be achieved through pairing with others. Once the communication has been encrypted, the Bluetooth LE devices could distribute the keys to save it for future connections. The last is better known as bonding. When two Bluetooth LE devices are bonded, in a future connection, they do not need to exchange the keys since they already know the shared secret, thus, they can encrypt the channel directly, saving time and power. However, if an attacker is listening to the first time that both (Central and Peripheral) Bluetooth LE devices enter into a connection state, the security of the link could be vulnerated, since the attacker could decipher the original message. Fortunately, Out Of Band (OOB) provides the ability (obviously, if both devices support it) to share the keys on an unknown medium for an attacker listening Bluetooth LE (for instance, NFC, SPI, UART, CAN, etc), increasing the security of the communication. This document explains how to enable OOB pairing on Bluetooth LE connectivity examples, basing on FRDM-KW36 SDK HID Host and HID Device examples.   Dedicated Macros and APIs for OOB Pairing The connectivity software stack contains macros and APIs that developers should implement to interact with the host stack and handle the events necessary for OOB. The following sections explain the main macros, variables, and APIs that manage OOB in our software.   Definitions and Variables gAppUsePairing_d It is used to enable or disable pairing to encrypt the link. Values Result 0 Pairing Disabled 1 Pairing Enabled   gAppUseBonding_d It is used to enable or disable bonding to request and save the keys for future connections. Values Result 0 Bonding Disabled 1 Bonding Enabled   gBleLeScOobHasMitmProtection_c This flag must be set if the application requires Man In the Middle protection, in other words, if the link must be authenticated. You can determine whether your software needs to set or clear this flag from the GAP Security Mode and Level. Red instances of the following table indicate that gBleLeScOobHasMitmProtection_c must be set to 1.   gPairingParameters This struct contains the pairing request or the pairing response (depending on the device's GAP role) payload. To enable and configure OOB pairing, oobAvailable field of the struct must be set to 1.   APIs bleResult_t Gap_ProvideOob (deviceId_t deviceId, uint8_t* aOob) This API must be implemented in response of gConnEvtOobRequest_c event in BleConnManager_GapPeripheralEvent or BleConnManager_GapCentralEvent functions (depending of the GAP role). This event only will be triggered if OOB is enabled and LE Legacy pairing is used. The gConnEvtOobRequest_c event occurs when the stack request the OOB data received from the peer device just after the gConnEvtPairingRequest_c or gConnEvtPairingResponse_c (depending of the GAP role). This API is valid only for LE Legacy pairing. Name of the Parameter Input/Output Description deviceId Input ID of the peer device aOob Input Pointer to OOB data previously received from the peer.   bleResult_t Gap_LeScGetLocalOobData (void) This API must be implemented either in response of gConnEvtPairingRequest_c or gConnEvtPairingResponse_c events  in BleConnManager_GapPeripheralEvent or BleConnManager_GapCentralEvent functions (depending of the GAP role) to get the local OOB data generated from the controller and in response of gLeScPublicKeyRegenerated_c event at BleConnManager_GenericEvent. Each time that Gap_LeScGetLocalOobData is executed in the application to obtain the OOB data, it triggers the gLeScLocalOobData_c generic event to inform that OOB data must be read from pGenericEvent->eventData.localOobData to send it to the peer device. This API is valid only for LE Secure Connections pairing.   bleResult_t Gap_LeScSetPeerOobData (deviceId_t deviceId, gapLeScOobData_t* pPeerOobData) This API must be implemented in response of gConnEvtLeScOobDataRequest_c event in BleConnManager_GapPeripheralEvent or BleConnManager_GapCentralEvent functions(depending of the GAP role). This event occurs when the stack requires the OOB data previously recieved from the peer. This API is valid only for LE Secure Connections pairing. Name of the Parameter Input/Output Description deviceId Input ID of the peer device aOob Input Pointer to gapLeScOobData_t struct that contains the OOB data received from the peer.   Enabling OOB on KW36 Bluetooth LE Peripheral Device The following example is based on the HID Device software included in the FRDM-KW36 SDK. It explains the minimum code needed to enable OOB. In the following sections, brown color indicates that such definition or API takes part in the stack and violet color indicates that such definition does not take part in the stack and its use is only for explanation purposes in this document.   Changes in app_preinclude.h file The app_preinclude.h header file contains definitions for the management of the application. To enable OOB pairing, you must ensure that gAppUseBonding_d and gAppUsePairing_d are set to 1. You can also set the value of the gBleLeScOobHasMitmProtection_c in this file, depending on the security mode and level needed in your application.  This example makes use of two custom definitions: gAppUseOob_d and gAppUseSecureConnections_d. Such definitions are used to explain how to enable/disable OOB and, if OOB is enabled, how to switch between LE Secure Connections pairing or LE Legacy paring.   /*! Enable/disable use of bonding capability */ #define gAppUseBonding_d 1 /*! Enable/disable use of pairing procedure */ #define gAppUsePairing_d 1 /*! Enable/disable use of privacy */ #define gAppUsePrivacy_d 0 #define gPasskeyValue_c 999999 /*! Enable/disable use of OOB pairing */ #define gAppUseOob_d 1 /*! Enable MITM protection when using OOB pairing */ #if (gAppUseOob_d) #define gBleLeScOobHasMitmProtection_c TRUE #endif /*! Enable/disable Secure Connections */ #define gAppUseSecureConnections_d 1‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍   Using the code above, you can enable or disable OOB using gAppUseOob_d, also you can decide whether to use LE Secure Connections (gAppUseSecureConnections_d = 1) or LE Legacy (gAppUseSecureConnections_d = 0)     Changes in app_config.c file The following portion fo code depicts how to fill gPairingParameters struct depending on which pairing method is used by the application.   /* SMP Data */ gapPairingParameters_t gPairingParameters = { .withBonding = (bool_t)gAppUseBonding_d, /* If Secure Connections pairing is supported, then set Security Mode 1 Level 4 */ /* If Legacy pairing is supported, then set Security Mode 1 Level 3 */ #if (gAppUseSecureConnections_d) .securityModeAndLevel = gSecurityMode_1_Level_4_c, #else .securityModeAndLevel = gSecurityMode_1_Level_3_c, #endif .maxEncryptionKeySize = mcEncryptionKeySize_c, .localIoCapabilities = gIoKeyboardDisplay_c, /* OOB Available enabled when app_preinclude.h file gAppUseOob_d macro is true */ .oobAvailable = (bool_t)gAppUseOob_d, #if (gAppUseSecureConnections_d) .centralKeys = (gapSmpKeyFlags_t) (gIrk_c), .peripheralKeys = (gapSmpKeyFlags_t) (gIrk_c), #else .centralKeys = (gapSmpKeyFlags_t) (gLtk_c | gIrk_c), .peripheralKeys = (gapSmpKeyFlags_t) (gLtk_c | gIrk_c), #endif /* Secure Connections enabled when app_preinclude.h file gAppUseSecureConnections_d macro is true */ .leSecureConnectionSupported = (bool_t)gAppUseSecureConnections_d, .useKeypressNotifications = FALSE, };‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍   Additionally, the serviceSecurity struct registers which are the security mode and level of each Bluetooth LE service, so if Secure Connections is selected (gAppUseSecureConnections_d = 1), mode = 1 level = 4.   static const gapServiceSecurityRequirements_t serviceSecurity[3] = { { .requirements = { #if (gAppUseSecureConnections_d) .securityModeLevel = gSecurityMode_1_Level_4_c, #else .securityModeLevel = gSecurityMode_1_Level_3_c, #endif .authorization = FALSE, .minimumEncryptionKeySize = gDefaultEncryptionKeySize_d }, .serviceHandle = (uint16_t)service_hid }, { .requirements = { #if (gAppUseSecureConnections_d) .securityModeLevel = gSecurityMode_1_Level_4_c, #else .securityModeLevel = gSecurityMode_1_Level_3_c, #endif .authorization = FALSE, .minimumEncryptionKeySize = gDefaultEncryptionKeySize_d }, .serviceHandle = (uint16_t)service_battery }, { .requirements = { #if (gAppUseSecureConnections_d) .securityModeLevel = gSecurityMode_1_Level_4_c, #else .securityModeLevel = gSecurityMode_1_Level_3_c, #endif .authorization = FALSE, .minimumEncryptionKeySize = gDefaultEncryptionKeySize_d }, .serviceHandle = (uint16_t)service_device_info } };‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍     Changes in ble_conn_manager.c file LE Legacy Pairing If your application will use LE Legacy Pairing, then you have to implement Gap_ProvideOob in response to the gConnEvtOobRequest_c event at the BleConnManager_GapPeripheralEvent function. In this example, gOobReceivedTKDataFromPeer is an array that stores the data previously received OOB from the peer device (using SPI, UART, I2C, etc), therefore, the procedure to fill this array with the data received from the peer depends entirely on your application. Notice that gOobReceivedTKDataFromPeer must contain the data received from the peer before to execute Gap_ProvideOob.   static uint8_t gOobReceivedTKDataFromPeer[16]; void BleConnManager_GapPeripheralEvent(deviceId_t peerDeviceId, gapConnectionEvent_t* pConnectionEvent) { switch (pConnectionEvent->eventType) { case gConnEvtConnected_c: { ... ... ... } break; ... ... ... #if (gAppUseOob_d && !gAppUseSecureConnections_d) case gConnEvtOobRequest_c: { /* The stack has requested the LE Legacy OOB data*/ (void)Gap_ProvideOob(peerDeviceId, &gOobReceivedTKDataFromPeer[0]); } break; #endif ... ... ... } }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍     LE Secure Connections Pairing When using Secure Connections Pairing, the application must handle two events at the BleConnManager_GapPeripheralEvent function. In gConnEvtPairingRequest_c event, you must implement Gap_LeScGetLocalOobData API to generate the local (r, Cr) values. The gConnEvtLeScOobDataRequest_c event indicates that the application is requesting the (r, Cr) values previously received OOB from the peer device (using SPI, UART, I2C, etc). Such values are contained into gOobReceivedRandomValueFromPeer and gOobReceivedConfirmValueFromPeer buffers. You must implement Gap_LeScSetPeerOobData in response to gConnEvtLeScOobDataRequest_c, This function has two parameters, the device ID of the peer and a pointer to a gapLeScOobData_t type struct. This struct is filled with the data contained in gOobReceivedRandomValueFromPeer and gOobReceivedConfirmValueFromPeer buffers.   gapLeScOobData_t gPeerOobData; static uint8_t gOobReceivedRandomValueFromPeer[gSmpLeScRandomValueSize_c]; /*!< LE SC OOB r (Random value) */ static uint8_t gOobReceivedConfirmValueFromPeer[gSmpLeScRandomConfirmValueSize_c]; /*!< LE SC OOB Cr (Random Confirm value) */ void BleConnManager_GapPeripheralEvent(deviceId_t peerDeviceId, gapConnectionEvent_t* pConnectionEvent) { switch (pConnectionEvent->eventType) { case gConnEvtConnected_c: { ... ... ... } break; case gConnEvtPairingRequest_c: { #if (defined(gAppUsePairing_d) && (gAppUsePairing_d == 1U)) gPairingParameters.centralKeys = pConnectionEvent->eventData.pairingEvent.centralKeys; (void)Gap_AcceptPairingRequest(peerDeviceId, &gPairingParameters); #if (gAppUseOob_d && gAppUseSecureConnections_d) /* The central has requested pairing, get local LE Secure Connections OOB data */ (void)Gap_LeScGetLocalOobData(); #endif #else (void)Gap_RejectPairing(peerDeviceId, gPairingNotSupported_c); #endif } break; ... ... ... #if (gAppUseOob_d && gAppUseSecureConnections_d) case gConnEvtLeScOobDataRequest_c: { /* The stack has requested the peer LE Secure Connections OOB data. Fill the gPeerOobData struct and provide it to the stack */ FLib_MemCpy(gPeerOobData.randomValue, &gOobReceivedRandomValueFromPeer[0], gSmpLeScRandomValueSize_c); FLib_MemCpy(gPeerOobData.confirmValue, &gOobReceivedConfirmValueFromPeer[0], gSmpLeScRandomConfirmValueSize_c); Gap_LeScSetPeerOobData(peerDeviceId, &gPeerOobData); } break; #endif ... ... ... } }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍   The gLeScPublicKeyRegenerated_c event in the BleConnManager_GenericEvent function must be handled using the Gap_LeScGetLocalOobData API as depicted below. Each time that Gap_LeScGetLocalOobData is executed by the software, it generates, asynchronously, the gLeScLocalOobData_c event (also handled in the BleConnManager_GenericEvent function) indicating that the local (r, Cr) values were successfully generated and you can read them using the pGenericEvent->eventData.localOobData pointer to send it OOB to the peer device. In this example, Oob_SendLocalRandomValueToPeer and Oob_SendLocalConfirmValueToPeer  are custom synchronous functions that demonstrate how you can implement a custom API that sends the local (r, Cr) read from pGenericEvent->eventData.localOobData pointer to the peer device using other protocols (SPI, UART, I2C, etc).   void BleConnManager_GenericEvent(gapGenericEvent_t* pGenericEvent) { switch (pGenericEvent->eventType) { case gInitializationComplete_c: { ... ... ... } break; ... ... ... #if (defined(gAppUsePairing_d) && (gAppUsePairing_d == 1U)) case gLeScPublicKeyRegenerated_c: { /* Key pair regenerated -> reset pairing counters */ mFailedPairings = mSuccessfulPairings = 0; /* Local Secure Connections OOB data must be refreshed whenever this event occurs */ #if (gAppUseOob_d && gAppUseSecureConnections_d) (void)Gap_LeScGetLocalOobData(); #endif } break; #endif ... ... ... #if (gAppUseOob_d && gAppUseSecureConnections_d) case gLeScLocalOobData_c: { /* Get the local Secure Connections OOB data and send to the peer */ Oob_SendLocalRandomValueToPeer((uint8_t*)pGenericEvent->eventData.localOobData.randomValue); Oob_SendLocalConfirmValueToPeer((uint8_t*)pGenericEvent->eventData.localOobData.confirmValue); } break; #endif ... ... ... } }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍     Enabling OOB on KW36 Bluetooth LE Central Device The following example is based on the HID Host software included in the FRDM-KW36 SDK. It explains the minimum code needed to enable OOB. In the following sections, brown color indicates that such definition or API takes part in the stack and violet color indicates that such definition does not take part in the stack and its use is only for explanation purposes in this document.   Changes in app_preinclude.h file The app_preinclude.h header file contains definitions for the management of the application. To enable OOB pairing, you must ensure that gAppUseBonding_d and gAppUsePairing_d are set to 1. You can also set the value of the gBleLeScOobHasMitmProtection_c in this file, depending on the security mode and level needed in your application.  This example makes use of two custom definitions: gAppUseOob_d and gAppUseSecureConnections_d. Such definitions are used to explain how to enable/disable OOB and, if OOB is enabled, how to switch between LE Secure Connections pairing or LE Legacy paring.   /*! Enable/disable use of bonding capability */ #define gAppUseBonding_d 1 /*! Enable/disable use of pairing procedure */ #define gAppUsePairing_d 1 /*! Enable/disable use of privacy */ #define gAppUsePrivacy_d 0 #define gPasskeyValue_c 999999 /*! Enable/disable use of OOB pairing */ #define gAppUseOob_d 1 /*! Enable MITM protection when using OOB pairing */ #if (gAppUseOob_d) #define gBleLeScOobHasMitmProtection_c TRUE #endif /*! Enable/disable Secure Connections */ #define gAppUseSecureConnections_d 1‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍   Using the code above, you can enable or disable OOB using gAppUseOob_d, also you can decide whether to use LE Secure Connections (gAppUseSecureConnections_d = 1) or LE Legacy (gAppUseSecureConnections_d = 0)     Changes in app_config.c file The following portion fo code depicts how to fill gPairingParameters struct depending on which pairing method is used by the application.   /* SMP Data */ gapPairingParameters_t gPairingParameters = { .withBonding = (bool_t)gAppUseBonding_d, /* If Secure Connections pairing is supported, then set Security Mode 1 Level 4 */ /* If Legacy pairing is supported, then set Security Mode 1 Level 3 */ #if (gAppUseSecureConnections_d) .securityModeAndLevel = gSecurityMode_1_Level_4_c, #else .securityModeAndLevel = gSecurityMode_1_Level_3_c, #endif .maxEncryptionKeySize = mcEncryptionKeySize_c, .localIoCapabilities = gIoKeyboardDisplay_c, /* OOB Available enabled when app_preinclude.h file gAppUseOob_d macro is true */ .oobAvailable = (bool_t)gAppUseOob_d, #if (gAppUseSecureConnections_d) .centralKeys = (gapSmpKeyFlags_t) (gIrk_c), .peripheralKeys = (gapSmpKeyFlags_t) (gIrk_c), #else .centralKeys = (gapSmpKeyFlags_t) (gLtk_c | gIrk_c), .peripheralKeys = (gapSmpKeyFlags_t) (gLtk_c | gIrk_c), #endif /* Secure Connections enabled when app_preinclude.h file gAppUseSecureConnections_d macro is true */ .leSecureConnectionSupported = (bool_t)gAppUseSecureConnections_d, .useKeypressNotifications = FALSE, };‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍     Changes in ble_conn_manager.c file LE Legacy Pairing If your application will use LE Legacy Pairing, then you have to implement Gap_ProvideOob in response to the gConnEvtOobRequest_c event at the BleConnManager_GapCentralEvent function. In this example, gOobOwnTKData is an array that stores the TK data which will be sent OOB to the peer device (using SPI, UART, I2C, etc)  and, at the same time, is the TK data that will be provided to the stack using Gap_ProvideOob. This data must be common on both Central and Peripheral devices, so the procedure to share the TK depends entirely on your application. Oob_SendLocalTKValueToPeer is a custom synchronous function that demonstrates how you can implement a custom API that sends the local TK to the peer device using other protocols (SPI, UART, I2C, etc).   static uint8_t gOobOwnTKData[16] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; void BleConnManager_GapCentralEvent(deviceId_t peerDeviceId, gapConnectionEvent_t* pConnectionEvent) { switch (pConnectionEvent->eventType) { case gConnEvtConnected_c: { ... ... ... } break; ... ... ... case gConnEvtPairingResponse_c: { /* Send Legacy OOB data to the peer */ #if (gAppUseOob_d & !gAppUseSecureConnections_d) Oob_SendLocalTKValueToPeer(&gOobOwnTKData[0]); #endif } break; ... ... ... #if (gAppUseOob_d && !gAppUseSecureConnections_d) case gConnEvtOobRequest_c: { /* The stack has requested the LE Legacy OOB data*/ (void)Gap_ProvideOob(peerDeviceId, &gOobOwnTKData[0]); } break; #endif‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ ... ... ... } }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍     LE Secure Connections Pairing When using Secure Connections Pairing, the application must handle two events at the BleConnManager_GapCentralEvent function. In gConnEvtPairingResponse_c event, you must implement Gap_LeScGetLocalOobData API to generate the local (r, Cr) values. The gConnEvtLeScOobDataRequest_c event indicates that the application is requesting the (r, Cr) values previously received OOB from the peer device (using SPI, UART, I2C, etc). Such values are contained into gOobReceivedRandomValueFromPeer and gOobReceivedConfirmValueFromPeer buffers. You must implement Gap_LeScSetPeerOobData in response to gConnEvtLeScOobDataRequest_c, This function has two parameters, the device ID of the peer and a pointer to a gapLeScOobData_t type struct. This struct is filled with the data contained in gOobReceivedRandomValueFromPeer and gOobReceivedConfirmValueFromPeer buffers.   gapLeScOobData_t gPeerOobData; static uint8_t gOobReceivedRandomValueFromPeer[gSmpLeScRandomValueSize_c]; /*!< LE SC OOB r (Random value) */ static uint8_t gOobReceivedConfirmValueFromPeer[gSmpLeScRandomConfirmValueSize_c]; /*!< LE SC OOB Cr (Random Confirm value) */ void BleConnManager_GapCentralEvent(deviceId_t peerDeviceId, gapConnectionEvent_t* pConnectionEvent) { switch (pConnectionEvent->eventType) { case gConnEvtConnected_c: { ... ... ... } break; ... ... ... case gConnEvtPairingResponse_c: { /* The peripheral has acepted pairing, get local LE Secure Connections OOB data */ #if (gAppUseOob_d && gAppUseSecureConnections_d) (void)Gap_LeScGetLocalOobData(); #endif } break; ... ... ... #if (gAppUseOob_d && gAppUseSecureConnections_d) case gConnEvtLeScOobDataRequest_c: { /* The stack has requested the peer LE Secure Connections OOB data. Fill the gPeerOobData struct and provide it to the stack */ FLib_MemCpy(gPeerOobData.randomValue, &gOobReceivedRandomValueFromPeer[0], gSmpLeScRandomValueSize_c); FLib_MemCpy(gPeerOobData.confirmValue, &gOobReceivedConfirmValueFromPeer[0], gSmpLeScRandomConfirmValueSize_c); Gap_LeScSetPeerOobData(peerDeviceId, &gPeerOobData); } break; #endif ... ... ... } }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍   The gLeScPublicKeyRegenerated_c event in the BleConnManager_GenericEvent function must be handled using the Gap_LeScGetLocalOobData API as depicted below. Each time that Gap_LeScGetLocalOobData is executed by the software, it generates, asynchronously, the gLeScLocalOobData_c event (also handled in the BleConnManager_GenericEvent function) indicating that the local (r, Cr) values were successfully generated and you can read them using the pGenericEvent->eventData.localOobData pointer to send it OOB to the peer device. In this example, Oob_SendLocalRandomValueToPeer and Oob_SendLocalConfirmValueToPeer  are custom synchronous functions that demonstrate how you can implement a custom API that sends the local (r, Cr) read from pGenericEvent->eventData.localOobData pointer to the peer device using other protocols (SPI, UART, I2C, etc).   void BleConnManager_GenericEvent(gapGenericEvent_t* pGenericEvent) { switch (pGenericEvent->eventType) { case gInitializationComplete_c: { ... ... ... } break; ... ... ... #if (defined(gAppUsePairing_d) && (gAppUsePairing_d == 1U)) case gLeScPublicKeyRegenerated_c: { /* Key pair regenerated -> reset pairing counters */ mFailedPairings = mSuccessfulPairings = 0; /* Local LE Secure Connections OOB data must be refreshed whenever this event occurs */ #if (gAppUseOob_d && gAppUseSecureConnections_d) (void)Gap_LeScGetLocalOobData(); #endif } break; #endif ... ... ... #if (gAppUseOob_d && gAppUseSecureConnections_d) case gLeScLocalOobData_c: { /* Get the local LE Secure Connections OOB data and send to the peer */ Oob_SendLocalRandomValueToPeer((uint8_t*)pGenericEvent->eventData.localOobData.randomValue); Oob_SendLocalConfirmValueToPeer((uint8_t*)pGenericEvent->eventData.localOobData.confirmValue); } break; #endif ... ... ... } }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍     Simplified Flow Diagram of OOB Central and Peripheral Events LE Legacy Pairing The following figure shows a simplified flow diagram of the LE Legacy OOB pairing example in this document. The LE Central device is the one that contains the OOB TK data that will be shared OOB using the custom Oob_SendLocalTKValueToPeer function. It must be implemented at the gConnEvtPairingResponse_c event to ensure that both devices know the OOB TK before to execute Gap_ProvideOob since this function requests this data. If the OOB data is correct on both sides, the pairing procedure ends, and it is noticed through gConnEvtPairingComplete_c. LE Secure Connections Pairing The following figure shows a simplified flow diagram of the LE Secure Connections OOB pairing example in this document. After both devices enter in connection, the data that will be shared OOB using the custom Oob_SendLocalRandomValueToPeer and Oob_SendLocalConfirmValueToPeer  functions is yielded by Gap_LeScGetLocalOobData on both sides. The last one must be implemented at gConnEvtPairingResponse_c and gConnEvtPairingRequest_c events to ensure that both devices know the Peripheral and Central (r, Cr) OOB data before to execute Gap_LeScSetPeerOobData since this function requests this data. If the OOB data is correct on both sides, the pairing procedure ends, and it is noticed through gConnEvtPairingComplete_c. This is how OOB pairing can be implemented in your project. I hope this document will be useful to you. Please, let us know any questions or comments. 
查看全文
The QN9090 is a Bluetooth Low Energy device that achieves ultra-low-power consumption and integrates an Arm ® Cortex ® -M4 CPU with a comprehensive mix of analog and digital peripherals. If the developer is working with the Development platform for QN9090 wireless MCUs for the first time, it is recommended to follow the QN9090-DK Development kit Getting Started (this guide can be found in QN9090DK Documentation section). This Quick Start document provides an overview about the QN9090 DK and its software tools and lists the steps to install the hardware and the software. For this document, Temperature Sensor and Temperature Collector examples will be used to demonstrate the implementation of a custom profile (both examples can be found in the SDK). This article will explain how to add the Humidity Profile and how to modify the code to get the Humidity Sensor and Collector working.   Introduction   Generic Attribute Profile (GATT) GATT defines the way that profile and user data are exchanged between devices over a BLE connection. GATT deals with actual data transfer procedures and formats. All standard BLE profiles are based on GATT and must comply with it to operate correctly, making it a key section of the BLE specification since every single item of data relevant to applications and users must be formatted, packed and sent according to the rules. There are two GATT roles that define the devices exchanging data: GATT Server This device contains a GATT Database and stores the data transported over the Attribute Protocol (ATT). The Server accepts ATT requests, commands and confirmations sent by the Client; and it can be configured to send data on its own through notifications and indications. GATT Client This is the “active” device that accesses data on the remote GATT Server via read, write, notify, or indicate operations. Notify and indicate operations are enabled by the client but initiated by the server, providing a way to push data to the client. Notifications are unacknowledged, while indications are acknowledged. Notifications are therefore faster, but less reliable. GATT Database establishes a hierarchy to organize attributes and is a collection of Services and Characteristics exposing meaningful data. Profiles are high level definitions that define how Services can be used to enable an application; Services are collections of Characteristics. Descriptors define attributes that describe a characteristic value.   Server (Sensor)   The Temperature Sensor project will be used as base to create our Humidity Custom Profile Server (Sensor). BLE SIG profiles Some Profiles or Services are already defined in the specification, and we can verify this in the Bluetooth SIG profiles document. Also, we need to check in the ble_sig_defines.h files (${workspace_loc:/${ProjName}/bluetooth/host/interface}) if this is already declared in the code. In this case, the Service is not declared, but the Characteristic of the humidity is declared in the specification. Then, we need to check if the Characteristic is already included in ble_sig_defines.h. Since the characteristic is not included, we define it as shown: /*! Humidity Characteristic UUID */ #define gBleSig_Humidity_d                   0x2A6FU GATT Database The Humidity Sensor will act as GATT Server since it will be the device containing all the information for the GATT Client. Temperature Sensor demo already implements the Battery Service and Device Information, so we only have to change the Temperature Service to Humidity Service.   In order to create the demo, we need to define a Service that must be the same as in the GATT Client, this is declared in the gatt_uuid128.h. If the new service is not the same, Client and Server will not be able to communicate each other. All macros, functions or structures in the SDK have a common template which helps the application to act accordingly. Hence, we need to define this service in the gatt_uui128.h as shown next: /* Humidity */ UUID128(uuid_service_humidity, 0xfe, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x02, 0x00, 0xfa, 0x10, 0x10) Units All the Services and Characteristics are declared in gatt_db.h. Descriptor are declared after the Characteristic Value declaration, but before the next Characteristic declaration. In this case the permission is the CharPresFormatDescriptor that have specific description by the standard. The Units for Humidity Characteristic is Percentage, defined in the Bluetooth SIG profiles document as 0x27AD. Descriptor Client Characteristic Configuration Descriptor (CCCD) is a descriptor where Clients write some of the bits to activate Server notifications and/or indications. PRIMARY_SERVICE_UUID128(service_humidity, uuid_service_humidity)        CHARACTERISTIC(char_humidity, gBleSig_Humidity_d, (gGattCharPropNotify_c))              VALUE(value_humidity, gBleSig_Humidity_d, (gPermissionNone_c), 2, 0x00, 0x25)              DESCRIPTOR(desc_humidity, gBleSig_CharPresFormatDescriptor_d, (gPermissionFlagReadable_c), 7, 0x0E, 0x00, 0xAD, 0x27, 0x00, 0x00, 0x00)              CCCD(cccd_humidity) Humidity service and interface Create a folder named “humidity” in path ${workspace_loc:/${ProjName}/bluetooth/profiles}. In the same path you can find the “temperature” folder; copy the temperature_service.c file and paste it inside the “humidity” folder with another name (humidity_service.c). After this, go back to the “temperature” folder and copy the temperature_interface.h file; paste it inside the “humidity” folder and rename it (humidity_interface.h). You will need to include the path of the created folder. Go to Project properties > C/C++ Build > Settings > Tool Settings > MCU C Compiler > Includes: Humidity Interface The humidity_interface.h file should include the following code, where the Service structure contains the Service handle and the initialization value: /*! Humidity Service - Configuration */ typedef struct humsConfig_tag {        uint16_t serviceHandle;        int16_t initialHumidity; } humsConfig_t; /*! Humidity Client - Configuration */ typedef struct humcConfig_tag {        uint16_t hService;        uint16_t hHumidity;        uint16_t hHumCccd;        uint16_t hHumDesc;        gattDbCharPresFormat_t humFormat; } humcConfig_t; Humidity service At minimum, humidity_service.c file must contain the following code: /*! Humidity Service - Subscribed Client*/ static deviceId_t mHums_SubscribedClientId; The Service stores the device identification for the connected client. This value is changed on subscription and non-subscription events. Initialization Initialization of the Service is made by calling the start procedure. This function is usually called when the application is initialized. In this case, this is done in the BleApp_Config() function. bleResult_t Hums_Start(humsConfig_t *pServiceConfig) {     mHums_SubscribedClientId = gInvalidDeviceId_c;     /* Set the initial value of the humidity characteristic */     return Hums_RecordHumidityMeasurement(pServiceConfig->serviceHandle,                                             pServiceConfig->initialHumidity); } Stop & Unsubscribe On stop function, the unsubscribe function is called. bleResult_t Hums_Stop(humsConfig_t *pServiceConfig) {     /* Stop functionality by unsubscribing */     return Hums_Unsubscribe(); } bleResult_t Hums_Unsubscribe(void) {     /* Unsubscribe by invalidating the client ID */     mHums_SubscribedClientId = gInvalidDeviceId_c;     return gBleSuccess_c; } Subscribe The subscribe function will be used in the main file to subscribe the GATT client to the Humidity Service. bleResult_t Hums_Subscribe(deviceId_t clientDeviceId) {     /* Subscribe by saving the client ID */     mHums_SubscribedClientId = clientDeviceId;     return gBleSuccess_c; } Record Humidity Depending on the complexity of the Service, the API will implement additional functions. For the Humidity Sensor will only have one Characteristic. The measurement will be saved on the GATT Database and send the notification to the Client. This function will need the Service handle and the new value as input parameters. bleResult_t Hums_RecordHumidityMeasurement(uint16_t serviceHandle, int16_t humidity) {        uint16_t handle;        bleResult_t result;        bleUuid_t uuid = Uuid16(gBleSig_Humidity_d);        /* Get handle of Humidity characteristic */        result = GattDb_FindCharValueHandleInService(serviceHandle,                      gBleUuidType16_c, &uuid, &handle);        if (result == gBleSuccess_c)        {              /* Update characteristic value */              result = GattDb_WriteAttribute(handle, sizeof(uint16_t), (uint8_t *)&humidity);              if (result == gBleSuccess_c)              {                     /* Notify the humidity value */                     Hts_SendHumidityMeasurementNotification(handle);              }        }        return result; } Remember to add/update the prototype for Initialization, Subscribe, Unsubscribe, Stop and Record Humidity Measurement functions in humidity_interface.h. Send notification After saving the measurement on the GATT Database by using the GattDb_WriteAttribute function, we can send the notification. To send this notification, first we have to get the CCCD and check if the notification is active after that; if it is active, then we send the notification. static void Hts_SendHumidityMeasurementNotification (              uint16_t handle ) {        uint16_t hCccd;        bool_t isNotificationActive;        /* Get handle of CCCD */        if (GattDb_FindCccdHandleForCharValueHandle(handle, &hCccd)                     != gBleSuccess_c)              return;        if (gBleSuccess_c == Gap_CheckNotificationStatus                     (mHums_SubscribedClientId, hCccd, &isNotificationActive) &&                     TRUE == isNotificationActive)        {              GattServer_SendNotification(mHums_SubscribedClientId, handle);        } } Remember to add or modify the prototype for Send Humidity Measurement Notification function.   Main file There are some modifications that need to be done in the Sensor main file: Add humidity_interface.h in main file /* Profile / Services */ #include "humidity_interface.h" Declare humidity service There are some modifications that have to be done in order to use the new Humidity Profile in the Sensor example. First, we need to declare the Humidity Service: static humsConfig_t humsServiceConfig = {(uint16_t)service_humidity, 0};   Rename BleApp_SendTemperature -> BleApp_SendHumidity static void BleApp_SendHumidity(void); After this, we need to add or modify the following functions and events: Modify BleApp_Start /* Device is connected, send humidity value */        BleApp_SendHumidity();   Ble_AppConfig Start Humidity Service and modify the Serial_Print line. /* Start services */ humsServiceConfig.initialHumidity = 0; (void)Hums_Start(&humsServiceConfig); (void)Serial_Print(gAppSerMgrIf, "\n\rHumidity sensor -> Press switch to start advertising.\n\r", gAllowToBlock_d);   BleApp_ConnectionCallback events - Event: gConnEvtConnected_c (void)Hums_Subscribe(peerDeviceId);   - Event: gConnEvtDisconnected_c (void)Hums_Unsubscribe();   Notify value in BleApp_GattServerCallback function /* Notify the humidity value when CCCD is written */ BleApp_SendHumidity(); Add the Hums_RecordHumidityMeasurement function and modify the initial value update in BleApp_SendHumidity function /* Update with initial humidity */ (void)Hums_RecordHumidityMeasurement((uint16_t)service_humidity,                                            (int16_t)(BOARD_GetTemperature())); Note: in this example, the Record Humidity uses the BOARD_GetTemperature to allow the developer to use the example without any external sensor and to be able to see a change in the collector, but in this section, there should be a GetHumidity function.   app_config.c file There are some modifications that need to be done inside app_config.c file: Modify Scanning and Advertising Data {     .length = NumberOfElements(uuid_service_humidity) + 1,     .adType = gAdComplete128bitServiceList_c,     .aData = (uint8_t *)uuid_service_humidity }   *Optional* Modify name {     .adType = gAdShortenedLocalName_c,     .length = 9,     .aData = (uint8_t*)"NXP_HUM" }   Modify Service Security Requirements {     .requirements = {         .securityModeLevel = gSecurityMode_1_Level_3_c,         .authorization = FALSE,         .minimumEncryptionKeySize = gDefaultEncryptionKeySize_d     },     .serviceHandle = (uint16_t)service_humidity }   Client (Collector)   We will use the Temperature Collector project as base to create our Humidity Custom Profile Client (Collector). BLE SIG profiles As mentioned in the Server section, we need to verify if the Profile or Service is already defined in the specification. For this, we can take a look at the Bluetooth SIG profiles document and check in the ble_sig_defines.h file (${workspace_loc:/${ProjName}/bluetooth/host/interface}) if this is already declared in the code. In our case, the Service is not declared, but the Characteristic of the Humidity is declared in the specification. Then, we need to check if the Characteristic is already included in ble_sig_defines.h. Since the Characteristic is not included, we need to define it as shown: /*! Humidity Characteristic UUID */ #define gBleSig_Humidity_d                    0x2A6FU GATT Database The Humidity Collector is going to have the GATT client; this is the device that will receive all new information from the GATT Server. The demo provided in this article works in the same way as the Temperature Collector. When the Collector enables the notifications from the Sensor, received notifications will be printed in the seral terminal. In order to create the demo, we need to define or develop a Service that must be the same as in the GATT Server, this is declared in the gatt_uuid128.h file. If the new Service is no the same, Client and Server will not be able to communicate each other. All macros, functions or structures in the SDK have a common template which helps the application to act accordingly. Hence, we need to define this service in the gatt_uui128.h as shown next: /* Humidity */ UUID128(uuid_service_humidity, 0xfe, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x02, 0x00, 0xfa, 0x10, 0x10) Includes After that, copy the humidity profile folder from the Sensor project and paste it into the Collector project inside ${workspace_loc:/${ProjName}/bluetooth/profiles}. Also, include the path of the new folder.   Main file In the Collector main file, we need to do some modifications to use the Humidity Profile Include humidity_interface.h /* Profile / Services */ #include "humidity_interface.h"   Modify the Custom Info of the Peer device humcConfig_t     humsClientConfig;   Modify BleApp_StoreServiceHandles function static void BleApp_StoreServiceHandles {     APP_DBG_LOG("");     uint8_t i,j;     if ((pService->uuidType == gBleUuidType128_c) &&              FLib_MemCmp(pService->uuid.uuid128, uuid_service_humidity, 16))     {         /* Found Humidity Service */        mPeerInformation.customInfo.humsClientConfig.hService = pService->startHandle;         for (i = 0; i < pService->cNumCharacteristics; i++)         {             if ((pService->aCharacteristics[i].value.uuidType == gBleUuidType16_c) &&                     (pService->aCharacteristics[i].value.uuid.uuid16 == gBleSig_Humidity_d))             {                 /* Found Humidity Char */             mPeerInformation.customInfo.humsClientConfig.hHumidity = pService->aCharacteristics[i].value.handle;                 for (j = 0; j < pService->aCharacteristics[i].cNumDescriptors; j++)                 {                     if (pService->aCharacteristics[i].aDescriptors[j].uuidType == gBleUuidType16_c)                     {                         switch (pService->aCharacteristics[i].aDescriptors[j].uuid.uuid16)                         {                             /* Found Humidity Char Presentation Format Descriptor */                             case gBleSig_CharPresFormatDescriptor_d:                             {                                 mPeerInformation.customInfo.humsClientConfig.hHumDesc = pService->aCharacteristics[i].aDescriptors[j].handle;                                 break;                             }                             /* Found Humidity Char CCCD */                             case gBleSig_CCCD_d:                             {                                 mPeerInformation.customInfo.humsClientConfig.hHumCccd = pService->aCharacteristics[i].aDescriptors[j].handle;                                 break;                             }                             default:                                 ; /* No action required */                                 break;                         }                     }                 }             }         }     } }   Modify BleApp_StoreDescValues function if (pDesc->handle == mPeerInformation.customInfo.humsClientConfig.hHumDesc) {        /* Store Humidity format*/        FLib_MemCpy(&mPeerInformation.customInfo.humsClientConfig.humFormat,                     pDesc->paValue,                     pDesc->valueLength); }   Implement BleApp_PrintHumidity function static void BleApp_PrintHumidity (     uint16_t humidity ) {     APP_DBG_LOG("");     shell_write("Humidity: ");     shell_writeDec((uint32_t)humidity);     /* Add '%' for Percentage - UUID 0x27AD.        www.bluetooth.com/specifications/assigned-numbers/units */     if (mPeerInformation.customInfo.humsClientConfig.humFormat.unitUuid16 == 0x27ADU)     {         shell_write(" %\r\n");     }     else     {         shell_write("\r\n");     } }   Modify BleApp_GattNotificationCallback function if (characteristicValueHandle == mPeerInformation.customInfo.humsClientConfig.hHumidity) { BleApp_PrintHumidity(Utils_ExtractTwoByteValue(aValue)); }   Modify CheckScanEvent function foundMatch = MatchDataInAdvElementList(&adElement, &uuid_service_humidity, 16);   Some events inside BleApp_StateMachineHandler need to be modified: BleApp_StateMachineHandler - Event: mAppIdle_c if (mPeerInformation.customInfo.humsClientConfig.hHumidity != gGattDbInvalidHandle_d)   - Event: mAppServiceDisc_c if (mPeerInformation.customInfo.humsClientConfig.hHumDesc != 0U)  mpCharProcBuffer->handle = mPeerInformation.customInfo.humsClientConfig.hHumDesc;   - Event: mAppReadDescriptor_c if (mPeerInformation.customInfo.humsClientConfig.hHumCccd != 0U)   Modify BleApp_ConfigureNotifications function mpCharProcBuffer->handle = mPeerInformation.customInfo.humsClientConfig.hHumCccd;   Demonstration   In order to print the relevant data in console, it may be necessary to disable Power Down mode in app_preinclude.h file. This file can be found inside source folder. For this, cPWR_UsePowerDownMode and cPWR_FullPowerDownMode should be set to 0. Now, after connection, every time that you press the User Interface Button on QN9090 Humidity Sensor is going to send the value to QN9090 Humidity Collector. Humidity Sensor   Humidity Collector  
查看全文
Introduction HCI Application is a Host Controller Interface application which provides a serial communication to interface with the KW40/KW41/KW35/KW36/QN9080 BLE radio part. It enables the user to have a way to control the radio through serial commands. The format of the HCI Command Packet it’s composed of the following parts:     Each command is assigned a 2 byte Opcode which it’s divided into two fields, called the OpCode Group Field (OGF) and OpCode Command Field (OCF). The OGF uses the upper 6 bits of the Opcode, while the OCF corresponds to the remaining 10 bits. The OGF of 0x3F is reserved for vendor-specific debug commands. The organization of the opcodes allows additional information to be inferred without fully decoding the entire Opcode. For further information regarding this topic, please check the BLUETOOTH SPECIFICATION Version 5.0 | Vol 2, Part E, 5.4 EXCHANGE OF HCI-SPECIFIC INFORMATION.   Adding HCI Custom Commands Example This document will guide you through the implementation of custom HCI commands in the KW36. For this example, we will include the following set of custom commands: 01 50 FC 00 – This command is to send a continuous unmodulated wave using a defined channel and output power (default: frequency 2.402GHz and PA_POWER register set to 0x3E).  01 4F FC 00 – This command is to stop the continuous unmodulated wave and configure the radio in Bluetooth LE mode again. This way you can continue sending adopted HCI commands. 01 00 FC 00 – Set the Channel 0 Freq 2402 MHz 01 01 FC 00 – Set the Channel 19 Freq 2440 MHz 01 02 FC 00 – Set the Channel 39 Freq 2480 MHz 01 10 FC 00 – Set the PA_POWER 1 01 11 FC 00 – Set the PA_POWER 32 01 12 FC 00 – Set the PA_POWER 62 The changes described in the following sections were based on the HCI Black Box SDK example (it is located at wireless_examples -> bluetooth -> hci_bb)   Changes in hci_transport.h The "hci_transport.h" file is located at bluetooth->hci_transport->interface folder. Include the following macros in ''Public constants and macros" #define gHciCustomCommandOpcodeUpper (0xFC50) #define gHciCustomCommandOpcodeLower (0xFC00) #define gHciInCustomVendorCommandsRange(x) (((x) <= gHciCustomCommandOpcodeUpper) && \ ((x) >= gHciCustomCommandOpcodeLower))‍‍‍‍‍‍‍‍ Declare a function to install the custom command as follows: void Hcit_InstallCustomCommandHandler(hciTransportInterface_t mCustomInterfaceHandler);‍   Changes in hcit_serial_interface.c The "hci_transport.h" file is located at bluetooth->hci_transport->source folder. Add the following in "Private memory declarations" static hciTransportInterface_t mCustomTransportInterface = NULL;‍ Modify the Hcit_SendMessage function as follows: static inline void Hcit_SendMessage(void) { uint16_t opcode = 0; /* verify if this is an event packet */ if(mHcitData.pktHeader.packetTypeMarker == gHciEventPacket_c) { /* verify if this is a command complete event */ if(mHcitData.pPacket->raw[0] == gHciCommandCompleteEvent_c) { /* extract the first opcode to verify if it is a custom command */ opcode = mHcitData.pPacket->raw[3] | (mHcitData.pPacket->raw[4] << 8); } } /* verify if command packet */ else if(mHcitData.pktHeader.packetTypeMarker == gHciCommandPacket_c) { /* extract opcode */ opcode = mHcitData.pPacket->raw[0] | (mHcitData.pPacket->raw[1] << 8); } if(gHciInCustomVendorCommandsRange(opcode)) { if(mCustomTransportInterface) { mCustomTransportInterface( mHcitData.pktHeader.packetTypeMarker, mHcitData.pPacket, mHcitData.bytesReceived); } } else { /* Send the message to HCI */ (void)mTransportInterface(mHcitData.pktHeader.packetTypeMarker, mHcitData.pPacket, mHcitData.bytesReceived); } mHcitData.pPacket = NULL; mPacketDetectStep = mDetectMarker_c; }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Develop the function to install the custom command as follows:   void Hcit_InstallCustomCommandHandler(hciTransportInterface_t mCustomInterfaceHandler) { OSA_InterruptDisable(); mCustomTransportInterface = mCustomInterfaceHandler; OSA_InterruptEnable(); }‍‍‍‍‍‍   Changes in hci_black_box.c This is the main application file, and it is located at source folder. Include the following files to support our HCI custom commands #include "hci_transport.h" #include "fsl_xcvr.h"‍‍ Define the following macros which represent the opcode for each custom command #define CUSTOM_HCI_CW_ON (0xFC50) #define CUSTOM_HCI_CW_OFF (0xFC4F) #define CUSTOM_HCI_CW_SET_CHN_0 (0xFC00) /*Channel 0 Freq 2402 MHz*/ #define CUSTOM_HCI_CW_SET_CHN_19 (0xFC01) /*Channel 19 Freq 2440 MHz*/ #define CUSTOM_HCI_CW_SET_CHN_39 (0xFC02) /*Channel 39 Freq 2480 MHz*/ #define CUSTOM_HCI_CW_SET_PA_PWR_1 (0xFC10) /*PA_POWER 1 */ #define CUSTOM_HCI_CW_SET_PA_PWR_32 (0xFC11) /*PA_POWER 32 */ #define CUSTOM_HCI_CW_SET_PA_PWR_62 (0xFC12) /*PA_POWER 62 */ #define CUSTOM_HCI_CW_EVENT_SIZE (0x04) #define CUSTOM_HCI_EVENT_SUCCESS (0x00) #define CUSTOM_HCI_EVENT_FAIL (0x01)‍‍‍‍‍‍‍‍‍‍‍ Add the following application variables static uint16_t channelCC = 2402; static uint8_t powerCC = 0x3E; uint8_t eventPacket[6] = {gHciCommandCompleteEvent_c, CUSTOM_HCI_CW_EVENT_SIZE, 1, 0, 0, 0 };‍‍‍‍‍‍ Declare the handler for our custom commands bleResult_t BleApp_CustomCommandsHandle(hciPacketType_t packetType, void* pPacket, uint16_t packetSize);‍ Find the "main_task" function, and register the handler for the custom commands through "Hcit_InstallCustomCommandHandler" function. You can include it just after BleApp_Init(); /* Initialize peripheral drivers specific to the application */ BleApp_Init(); /* Register the callback for the custom commands */ Hcit_InstallCustomCommandHandler((hciTransportInterface_t)&BleApp_CustomCommandsHandle); /* Create application event */ mAppEvent = OSA_EventCreate(TRUE); if( NULL == mAppEvent ) { panic(0,0,0,0); return; }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Develop the handler of our custom commands as follows: bleResult_t BleApp_CustomCommandsHandle(hciPacketType_t packetType, void* pPacket, uint16_t packetSize) { uint16_t opcode = 0; if(gHciCommandPacket_c == packetType) { opcode = ((uint8_t*)pPacket)[0] | (((uint8_t*)pPacket)[1] << 8); switch(opcode) { /*@CC: Set Channel */ case CUSTOM_HCI_CW_SET_CHN_0: /*@CC: Set Channel 0 Freq 2402 MHz */ channelCC=2402; break; case CUSTOM_HCI_CW_SET_CHN_19: /*@CC: Channel 19 Freq 2440 MHz*/ channelCC=2440; break; case CUSTOM_HCI_CW_SET_CHN_39: /*@CC: Channel 39 Freq 2480 MHz */ channelCC=2480; break; /*@CC: Set PA_POWER */ case CUSTOM_HCI_CW_SET_PA_PWR_1: /*@CC: Set PA_POWER 1 */ powerCC=0x01; break; case CUSTOM_HCI_CW_SET_PA_PWR_32: /*@CC: Set PA_POWER 32 */ powerCC=0x20; break; case CUSTOM_HCI_CW_SET_PA_PWR_62: /*@CC: Set PA_POWER 62 */ powerCC=0x3E; break; /*@CC: Generate a Continuous Unmodulated Signal ON / OFF */ case CUSTOM_HCI_CW_ON: /*@CC: Generate a Continuous Unmodulated Signal when pressing SW3 */ XCVR_DftTxCW(channelCC, 6); XCVR_ForcePAPower(powerCC); break; case CUSTOM_HCI_CW_OFF: /*@CC: Turn OFF the transmitter */ XCVR_ForceTxWd(); /* Initialize the PHY as BLE */ XCVR_Init(BLE_MODE, DR_1MBPS); break; default: eventPacket[5] = CUSTOM_HCI_EVENT_FAIL; break; } eventPacket[3] = (uint8_t)opcode; eventPacket[4] = (uint8_t)(opcode >> 8); eventPacket[5] = CUSTOM_HCI_EVENT_SUCCESS; Hcit_SendPacket(gHciEventPacket_c, eventPacket, sizeof(eventPacket)); } else { return gBleUnexpectedError_c; } return gBleSuccess_c; }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍   Testing Custom HCI Commands Using NXP Test Tool 12 To test HCI Black Box software, we need to install NXP Test Tool 12, from the NXP Semiconductors | Automotive, Security, IoT official web site. Once you have installed Test Tool, attach the FRDM-KW36 board to your PC and open the serial port enumerated in the start page clicking twice on the icon. Then, select "Raw Data" checkbox and type any of our custom commands, for instance, "01 01 FC 00" (Set the Channel 19 Freq 2440 MHz). Shift out the command clicking on the "Send Raw..." button. You will see the HCI Tx and Rx in the right upper corner of your screen
查看全文