Smart Bluetooth Forum Discussions
text.format{('custom.tabs.no.results')}
Is there any debug possibility
UART?
From the code : ble_trace0 - ble_trace6 used to log the prints but it is defined dummy in bleapp.h
Is that legacy code ?
Show LessI can't get the demo app to connect to the WICED Sense device.
The Android app runs.... I see the gauges and dials but they don't move or work in any way... under the Android settings page I see that it has paired to the device... I press the 'Connect' button on the app and it goes dark for about 15 seconds, then comes back to 'white'.
This same WICED Sense pairs with an iPhone without a problem.
Any suggestions?
Details:
Platform is: Nexus 7 running Android v 4.4.4
Show LessI have a Android Mobile V4.2 Jelly Bean. The app developed will work for android versions 4.3 & above, which version of demo app should I use to get a sense of this Wiced Sense
Show LessHi,
I'm going to use several GPIO pin as Data Input with interrupt by register handler in following function.
gpio_registerForInterrupt(interrupt_handler_mask, application_gpio_interrupt_handler);
Then, in the application_gpio_interrupt_handler(), as the document example is:
void application_gpio_interrupt_handler(void* parameter)
Question 1:
Can the "parameter" be used to identify the pin which trigger an interrupt? and identify that is triggered at falling edge or rising edge?
Or is there any API to identify it? I found gpio_getPortInterruptStatus but not sure this is.
Question 2:
Do the handler need to clear interrupt by gpio_clearPortInterruptStatus before exit the handler?
Thank you!
Show LessLooks like the dependency mechanism is broken in SDK 2.1.1/Win7. The .d files are being created but changes to headers are not triggering rebuilds as expected. This has bit me a couple of times.
Show LessPreface
I2C Timing of EEPROM
State Machines of Emulation Code
Porting Steps
Debug Code
Generate the BCM2073x Image Array
Get the Emulation Code
Preface
If BCM2073x connects a powerful host MCU and the host MCU has a big capacity memory, it’s possible to store the BCM2073x image in the host MCU memory. But the host MCU usually does not have I2C slave port, so we implement the code to emulate I2C slave timing of EEPROM by using two GPIOs on host MCU side. This document introduces how to port the emulation code for different MCU.
Note:
- The code only emulates reading data from EEPROM, because it’s difficulty to catch the I2C slave timing when writing data to EEPROM.
- Detect the SCL/SDA level by polling in emulation code. Please disable the interrupt when running the simulation code, because one or more I2C SDA/SCL bit will be missed when executing the ISR. The valid level of SCL/SDA only keeps 5us when I2C speed is 100K, and only keeps 1.25us when I2C speed is 400K.
- The emulation code needs fine-tune after porting based on different HW.
I2C Timing of EEPROM
The following figures are the timing of read or write EEPROM, please refer to EEPROM datasheet to get more information.
1. Random Read
2. Sequential Read
3. Byte Write
4. Page Write
State Machines of Emulation Code
The emulation code runs on host MCU side only for reading the BCM2073x image from the host MCU memory. BCM2073x loads the image from EEPROM by “Random Read” or “Sequential Read”.
The following is the state machines of emulation code.
- SM1 - Idle
- SM2 - Receive device address from BCM2073x
- SM3 - Receive the data address from BCM2073x
- SM4 - Send data to BCM2073x
SM1 - Idle
Detect I2C start bit, transfer to SM2 if found the I2C start bit, or exit the simulation if not detect the start bit after idle timer timeout expires.
SM2 – Receive device address from BCM2073x
Receive the device address, transfer to SM1 if device address isn’t matched, or transfer to SM3 if the device address is matched.
SM3 – Receive data address from BCM2073x
Receive the two byte data address, transfer to SM4 if the correct address is gotten.
SM4 – Send data to BCM2073x
Send one byte data to BCM2073x, transfer to SM1 if got the I2C stop bit, or keep the SM4 and continue to send more data if ACK is received.
Porting Steps
1. Re-write the following functions.
void scl_sda_init(void)
BYTE get_scl(void)
BYTE get_sda(void)
void set_sda(void)
void change_sda_to_output(void)
void change_sda_to_input(void)
void scl_sda_follow_init(void)
void scl_follow_high(void)
void scl_follow_low(void)
void sda_follow_high(void)
void sda_follow_low(void)
2. Re-define the follow timeout.
#define SCL_HIGH_TIMEOUT 200
#define SCL_LOW_TIMEOUT 200
#define STOP_TIMEOUT 1000
#define START_TIMEOUT 1000
#define IDLE_TIMEOUT 5000 // 2s
3. Change the WICED Smart Code to make the corresponding BCM2073x image.
- Enable the RAMBUFENABLE macro in sparinit.c, use the RAM to store the data that wrote to NVRAM (VS section in EEPROM).
- Change the I2C speed from 400K to 100K in the mandatory.cgs if can’t catch the I2C 400K timing.
Debug Code
Don’t use functions that like “printf” to debug code, because the SCL/SDA bit will be missed when executing these functions.
Suggest using the following ways to debug code.
- Use another two GPIOs to sync the SCL/SDA timing in the I2C communication, named the two GPIO as following SCL/SDA. We can look the waveform of following SCL/SDA to judge whether code is correct or not. If the waveform of following SCL/SDA matches the waveform of original SCL/SDA, it means the emulation works correctly.
- Save the running information in the temporary variants when running the emulation code, and print the variants when exited the emulation.
Generate the BCM2073x Image Array
If the host MCU has file system, you can directly store the BCM20732 binary image (*.bin) in the file system. If the host MCU does not have the file system, we usually use an array to store the BCM20732 image in MCU memory. Refer to the following steps to generate the BCM2073x image array.
- Run windows console on PC.
- Covert image from HEX format to BIN format.
ihex2bin.exe -f 0x00 xxx.hex xxx.bin
3. Covert BIN image to an array.
bin2c -m 128 xxx.bin xxx.h xxx_image
4. You can find the image array named xxx_image in xxx.h.
Show LessOverview
The GATT DB(Database) is an important data structure of the WICED Smart application, please refer to “Create GATT Database” for GATT DB description. This document introduces GATT DB definition, initialization, work flow and APIs.
GATT DB Definition
The GATT DB definition usually is in the beginning of application code, the following sample is in hello_sensor.c.
const UINT8 hello_sensor_gatt_database[]=
{
// Handle 0x01: GATT service
// Service change characteristic is optional and is not present
PRIMARY_SERVICE_UUID16 (0x0001, UUID_SERVICE_GATT),
// Handle 0x14: GAP service
// Device Name and Appearance are mandatory characteristics. Peripheral
// Privacy Flag only required if privacy feature is supported. Reconnection
// Address is optional and only when privacy feature is supported.
// Peripheral Preferred Connection Parameters characteristic is optional
// and not present.
PRIMARY_SERVICE_UUID16 (0x0014, UUID_SERVICE_GAP),
// Handle 0x15: characteristic Device Name, handle 0x16 characteristic value.
// Any 16 byte string can be used to identify the sensor. Just need to
// replace the "Hello" string below. Keep it short so that it fits in
// advertisement data along with 16 byte UUID.
CHARACTERISTIC_UUID16 (0x0015, 0x0016, UUID_CHARACTERISTIC_DEVICE_NAME,
LEGATTDB_CHAR_PROP_READ, LEGATTDB_PERM_READABLE, 16),
'H','e','l','l','o',0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// Handle 0x17: characteristic Appearance, handle 0x18 characteristic value.
// List of approved appearances is available at bluetooth.org. Current
// value is set to 0x200 - Generic Tag
CHARACTERISTIC_UUID16 (0x0017, 0x0018, UUID_CHARACTERISTIC_APPEARANCE,
LEGATTDB_CHAR_PROP_READ, LEGATTDB_PERM_READABLE, 2),
BIT16_TO_8(APPEARANCE_GENERIC_TAG),
// Handle 0x28: Hello Service.
// This is the main proprietary service of Hello Sensor. It has 2 characteristics.
// One will be used to send notification(s) to the paired client when button is
// pushed, another is a configuration of the device. The only thing which
// can be configured is number of times to send notification. Note that
// UUID of the vendor specific service is 16 bytes, unlike standard Bluetooth
// UUIDs which are 2 bytes. _UUID128 version of the macro should be used.
PRIMARY_SERVICE_UUID128 (HANDLE_HELLO_SENSOR_SERVICE_UUID, UUID_HELLO_SERVICE),
// Handle 0x29: characteristic Hello Notification, handle 0x2a characteristic value
// we support both notification and indication. Peer need to allow notifications
// or indications by writing in the Characteristic Client Configuration Descriptor
// (see handle 2b below). Note that UUID of the vendor specific characteristic is
// 16 bytes, unlike standard Bluetooth UUIDs which are 2 bytes. _UUID128 version
// of the macro should be used.
CHARACTERISTIC_UUID128 (0x0029, HANDLE_HELLO_SENSOR_VALUE_NOTIFY, UUID_HELLO_CHARACTERISTIC_NOTIFY,
LEGATTDB_CHAR_PROP_READ | LEGATTDB_CHAR_PROP_NOTIFY | LEGATTDB_CHAR_PROP_INDICATE,
LEGATTDB_PERM_READABLE, 7),
'H','e','l','l','o',' ','0',
// Handle 0x2b: Characteristic Client Configuration Descriptor.
// This is standard GATT characteristic descriptor. 2 byte value 0 means that
// message to the client is disabled. Peer can write value 1 or 2 to enable
// notifications or indications respectively. Not _WRITABLE in the macro. This
// means that attribute can be written by the peer.
CHAR_DESCRIPTOR_UUID16_WRITABLE (HANDLE_HELLO_SENSOR_CLIENT_CONFIGURATION_DESCRIPTOR,
UUID_DESCRIPTOR_CLIENT_CHARACTERISTIC_CONFIGURATION,
LEGATTDB_PERM_READABLE | LEGATTDB_PERM_WRITE_REQ, 2),
0x00,0x00,
// Handle 0x2c: characteristic Hello Configuration, handle 0x2d characteristic value
// The configuration consists of 1 bytes which indicates how many notifications or
// indications to send when user pushes the button.
CHARACTERISTIC_UUID128_WRITABLE (0x002c, HANDLE_HELLO_SENSOR_CONFIGURATION, UUID_HELLO_CHARACTERISTIC_CONFIG,
LEGATTDB_CHAR_PROP_READ | LEGATTDB_CHAR_PROP_WRITE,
LEGATTDB_PERM_READABLE | LEGATTDB_PERM_WRITE_CMD | LEGATTDB_PERM_WRITE_REQ, 1),
0x00,
// Handle 0x4d: Device Info service
// Device Information service helps peer to identify manufacture or vendor
// of the device. It is required for some types of the devices (for example HID,
// and medical, and optional for others. There are a bunch of characteristics
// available, out of which Hello Sensor implements 3.
PRIMARY_SERVICE_UUID16 (0x004d, UUID_SERVICE_DEVICE_INFORMATION),
// Handle 0x4e: characteristic Manufacturer Name, handle 0x4f characteristic value
CHARACTERISTIC_UUID16 (0x004e, 0x004f, UUID_CHARACTERISTIC_MANUFACTURER_NAME_STRING, LEGATTDB_CHAR_PROP_READ, LEGATTDB_PERM_READABLE, 8),
'B','r','o','a','d','c','o','m',
// Handle 0x50: characteristic Model Number, handle 0x51 characteristic value
CHARACTERISTIC_UUID16 (0x0050, 0x0051, UUID_CHARACTERISTIC_MODEL_NUMBER_STRING, LEGATTDB_CHAR_PROP_READ, LEGATTDB_PERM_READABLE, 8),
'1','2','3','4',0x00,0x00,0x00,0x00,
// Handle 0x52: characteristic System ID, handle 0x53 characteristic value
CHARACTERISTIC_UUID16 (0x0052, 0x0053, UUID_CHARACTERISTIC_SYSTEM_ID, LEGATTDB_CHAR_PROP_READ, LEGATTDB_PERM_READABLE, 8),
0x93,0xb8,0x63,0x80,0x5f,0x9f,0x91,0x71,
// Handle 0x61: Battery service
// This is an optional service which allows peer to read current battery level.
PRIMARY_SERVICE_UUID16 (0x0061, UUID_SERVICE_BATTERY),
// Handle 0x62: characteristic Battery Level, handle 0x63 characteristic value
CHARACTERISTIC_UUID16 (0x0062, 0x0063, UUID_CHARACTERISTIC_BATTERY_LEVEL,
LEGATTDB_CHAR_PROP_READ, LEGATTDB_PERM_READABLE, 1),
0x64,
};
BLE stack calls the APPLICATION_INIT to get the GATT DB configuration and initialize GATT DB before application runs. The following sample code is in hello_sensor.c.
APPLICATION_INIT()
{
bleapp_set_cfg((UINT8 *)hello_sensor_gatt_database,
sizeof(hello_sensor_gatt_database),
(void *)&hello_sensor_cfg,
(void *)&hello_sensor_puart_cfg,
(void *)&hello_sensor_gpio_cfg,
hello_sensor_create);
}
GATT DB Working Flow
The following figure is the GATT DB working flow.
Client is able to read the data from the GATT DB after the server writes data to GATT DB. But server does not need to know how and when client's read is performed.
Client write data to GATT DB, the write callback function is called on server side, server read data from the GATT DB in callback function. If client write requires an acknowledgement, it is done by the stack without server being involved.
APIs for Server Role
INT32 bleprofile_ReadHandle(UINT16 hdl, BLEPROFILE_DB_PDU *p_pdu);
Read data from GATT DB.
INT32 bleprofile_WriteHandle(UINT16 hdl, BLEPROFILE_DB_PDU *p_pdu);
Write data to GATT DB.
void bleprofile_sendIndication(UINT16 attrHandle, UINT8 *attr, INT32 len, LEATT_NO_PARAM_CB cb);
Send an Indication to client.
Client sends back acknowledgement if it received the indication, sever will call the callback function “cb” if it receives the acknowledgement. Server should not send next indication until previous one has been acknowledged.
void bleprofile_sendNotification(UINT16 attrHandle, UINT8 *attr, INT32 len);
Send a notification to client. The notification does NOT need confirmation.
INT32 legattdb_regWriteHandleCb(LEGATTDB_WRITE_CB cb);
Register write callback function for GATT DB. The callback function “cb” will be called when client write data to GATT DB.
APIs for Client Role
void bleprofile_sendWriteReq(UINT16 attrHandle, UINT8 *attr, INT32 len);
Send write request to server.
Before calling this function, application can register a callback function to receive notification with write result by function leatt_regWriteRspCb.
void bleprofile_sendWriteCmd(UINT16 attrHandle, UINT8 *data, INT32 len);
Send write command to server.
void bleprofile_sendReadReq(UINT16 Handle);
Send read request to server.
Before calling this function, application typically register a callback function to receive notification with read result by function leatt_regReadRspCb.
void bleprofile_sendReadByTypeReq(UINT16 startHandle, UINT16 endHandle, UINT16 uuid16);
Send read request to server by type.
Before calling this function, application typically register a callback function to receive notification with read result by function leatt_regReadByTypeRspCb. This function usually is called by the client during GATT discovery.
void bleprofile_sendReadByGroupTypeReq(UINT16 startHandle, UINT16 endHandle, UINT16 uuid16);
Send read request to server by group type.
Before calling this function, application typically register a callback function to receive notification with read result by function leatt_regReadByGroupTypeRspCb. This function usually is called by the client during GATT discovery.
void bleprofile_sendHandleValueConf(void);
Send acknowledgement to server if received the indication.
Show LessBLE Data Exchange
Please read section BLE Data Exchange in document How-to-Write-WICED-Smart-Applications.pdf(in directory of WICED-Smart-SDK\Doc). Make sure you understand what Attribute, Characteristic, Descriptor, Service, Profile are.
GATT Database Access
Please read section GATT Database in document How-to-Write-WICED-Smart-Applications.pdf.
GATT Database Structure
Please read through section Create a GATT Database in the BLE Application in document How-to-Write-WICED-Smart-Applications.pdf. Try to find answers to the following questions:
- What is the difference between 16-bits and 128-bits UUID?
- What’s the data length of a handle of characteristic?
- What’s the purpose of a handle compared with UUID?
- Why does a characteristic have two handles?
- Are services UUID_SERVICE_GATT and UUID_SERVICE_GAP mandatory for each of BLE device?
Properties and Permissions
Section 3.3.1.1 Characteristic Properties in Bluetooth Core Specification v4.0 helps to understand the following definitions that are required to describe properties a characteristic.
LEGATTDB_CHAR_PROP_BROADCAST | Permits the broadcast of characteristic value |
LEGATTDB_CHAR_PROP_READ | Permits the read of the characteristic value |
LEGATTDB_CHAR_PROP_WRITE_NO_RESPONSE | Permits the write of the characteristic value without response |
LEGATTDB_CHAR_PROP_WRITE | Permits the write of the characteristic value with response |
LEGATTDB_CHAR_PROP_NOTIFY | Permits the notification of the characteristic value without acknowledgement |
LEGATTDB_CHAR_PROP_INDICATE | Permits the indication of the characteristic value with acknowledgement |
LEGATTDB_CHAR_PROP_AUTHD_WRITES | Permits signed writes to the characteristic value |
LEGATTDB_CHAR_PROP_EXTENDED | Additional characteristic properties are defined |
Section 3.2.5 Attribute Permissions in Bluetooth Core Specification v4.0 helps to understand the following definitions that are required to describe permissions a characteristic.
LEGATTDB_PERM_NONE | Characteristic value is not readable or writable (can support indication or notification) |
LEGATTDB_PERM_VARIABLE_LENGTH | Characteristic value can be a variable-length array |
LEGATTDB_PERM_READABLE | Permits the read of the characteristic value |
LEGATTDB_PERM_WRITE_CMD | Permits the write of the characteristic value without response |
LEGATTDB_PERM_WRITE_REQ | Permits the write of the characteristic value with response |
LEGATTDB_PERM_AUTH_READABLE | Permits the authenticated read operation |
LEGATTDB_PERM_RELIABLE_WRITE | Permits reliable write operation |
LEGATTDB_PERM_AUTH_WRITABLE | Permits authenticated write operation |
Create a GATT Database
A GATT database can be found in file hello_sensor.c of application Hello Sensor. Remove comments then we can get the definition of GATT database for example application hello_sensor as showed in Figure 1. Macro CHARACTERISTIC_UUID16* or CHARACTERISTIC_UUID128* add a characteristic to a previously defined service. Macro CHAR_DESCRIPTOR_UUID16* adds a characteristic descriptor to a previously defined characteristic.
const UINT8 hello_sensor_gatt_database[]=
{
PRIMARY_SERVICE_UUID16 (0x0001, UUID_SERVICE_GATT),
PRIMARY_SERVICE_UUID16 (0x0014, UUID_SERVICE_GAP),
CHARACTERISTIC_UUID16 (0x0015, 0x0016, UUID_CHARACTERISTIC_DEVICE_NAME, LEGATTDB_CHAR_PROP_READ,
LEGATTDB_PERM_READABLE, 16), 'H','e','l','l','o',0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
CHARACTERISTIC_UUID16 (0x0017, 0x0018, UUID_CHARACTERISTIC_APPEARANCE,
LEGATTDB_CHAR_PROP_READ, LEGATTDB_PERM_READABLE, 2), BIT16_TO_8(APPEARANCE_GENERIC_TAG),
PRIMARY_SERVICE_UUID128 (HANDLE_HELLO_SENSOR_SERVICE_UUID, UUID_HELLO_SERVICE),
CHARACTERISTIC_UUID128 (0x0029, HANDLE_HELLO_SENSOR_VALUE_NOTIFY, UUID_HELLO_CHARACTERISTIC_NOTIFY,
LEGATTDB_CHAR_PROP_READ | LEGATTDB_CHAR_PROP_NOTIFY | LEGATTDB_CHAR_PROP_INDICATE,
LEGATTDB_PERM_READABLE, 7), 'H','e','l','l','o',' ','0',
CHAR_DESCRIPTOR_UUID16_WRITABLE (HANDLE_HELLO_SENSOR_CLIENT_CONFIGURATION_DESCRIPTOR,
UUID_DESCRIPTOR_CLIENT_CHARACTERISTIC_CONFIGURATION,
LEGATTDB_PERM_READABLE | LEGATTDB_PERM_WRITE_REQ, 2), 0x00,0x00,
CHARACTERISTIC_UUID128_WRITABLE (0x002c, HANDLE_HELLO_SENSOR_CONFIGURATION, UUID_HELLO_CHARACTERISTIC_CONFIG,
LEGATTDB_CHAR_PROP_READ | LEGATTDB_CHAR_PROP_WRITE,
LEGATTDB_PERM_READABLE | LEGATTDB_PERM_WRITE_CMD | LEGATTDB_PERM_WRITE_REQ, 1), 0x00,
PRIMARY_SERVICE_UUID16 (0x004d, UUID_SERVICE_DEVICE_INFORMATION),
CHARACTERISTIC_UUID16 (0x004e, 0x004f, UUID_CHARACTERISTIC_MANUFACTURER_NAME_STRING, LEGATTDB_CHAR_PROP_READ,
LEGATTDB_PERM_READABLE, 8), 'B','r','o','a','d','c','o','m',
CHARACTERISTIC_UUID16 (0x0050, 0x0051, UUID_CHARACTERISTIC_MODEL_NUMBER_STRING, LEGATTDB_CHAR_PROP_READ,
LEGATTDB_PERM_READABLE, 8), '1','2','3','4',0x00,0x00,0x00,0x00,
CHARACTERISTIC_UUID16 (0x0052, 0x0053, UUID_CHARACTERISTIC_SYSTEM_ID, LEGATTDB_CHAR_PROP_READ,
LEGATTDB_PERM_READABLE, 8), 0x93,0xb8,0x63,0x80,0x5f,0x9f,0x91,0x71,
PRIMARY_SERVICE_UUID16 (0x0061, UUID_SERVICE_BATTERY),
CHARACTERISTIC_UUID16 (0x0062, 0x0063, UUID_CHARACTERISTIC_BATTERY_LEVEL,
LEGATTDB_CHAR_PROP_READ, LEGATTDB_PERM_READABLE, 1), 0x64,
};
Figure 1 Definition of Hello Sensor GATT database
Following is the hierarchy diagram that reflects above definition.
Figure 2 Hierarchy of Hello Sensor GATT Database
Figure 3 shows the breakdown of characteristic definition. Please make sure the value and the length of the value match. Macro CHARACTERISTIC_UUID128_WRITABLE should be used to define a writable 128-bits characteristic instead of CHARACTERISTIC_UUID128.
Figure 3 Breakdown of Characteristic Definition
One or more descriptors can exist in each characteristic definition. Possible descriptors are defined in the Bluetooth specification. Please refer to 3.3.3 Characteristic Descriptor Declarations[vol 3] in Bluetooth Core Specification V4.0 to understand the following C programming definition.
enum ble_uuid_characteristic_descriptor
{
UUID_DESCRIPTOR_CHARACTERISTIC_EXTENDED_PROPERTIES = 0x2900,
UUID_DESCRIPTOR_CHARACTERISTIC_USER_DESCRIPTION = 0x2901,
UUID_DESCRIPTOR_CLIENT_CHARACTERISTIC_CONFIGURATION = 0x2902,
UUID_DESCRIPTOR_SERVER_CHARACTERISTIC_CONFIGURATION = 0x2903,
UUID_DESCRIPTOR_CHARACTERISTIC_PRESENTATION_FORMAT = 0x2904,
UUID_DESCRIPTOR_CHARACTERISTIC_AGGREGATE_FORMAT = 0x2905,
UUID_DESCRIPTOR_VALID_RANGE = 0x2906,
UUID_DESCRIPTOR_EXTERNAL_REPORT_REFERENCE = 0x2907,
UUID_DESCRIPTOR_REPORT_REFERENCE = 0x2908,
//0.9, added after tapeout
UUID_DESCRIPTOR_NUMBER_OF_DIGITALS = 0x2909,
UUID_DESCRIPTOR_TRIGGER_SETTING = 0x290A,
};
Figure 4 Standard Characteristic Descriptors
Examine a GATT Database
You can dump the content of GATT database during runtime for debug. Figure 5 shows the output of debug UART after calling function legattdb_dumpDb().
14:46:36 - 0118
14:46:36 - 0018
14:46:36 - 021600002a
14:46:36 - 48656c6c6f0000000000000000000000
14:46:36 - 021800012a
14:46:36 - 0002
14:46:36 - 2320567c05cf6eb4c341772851827e1b
14:46:36 - 322a0026f6699168eec2be444db95c3f
14:46:36 - 2dc38a
14:46:36 - 48656c6c6f2031
14:46:36 - 0000
14:46:36 - 0a2d001a89074a2f3b7ea681443ff9a8
14:46:36 - f29b5e
14:46:36 - 00
14:46:36 - 48656c6c6f20436f6e666967
14:46:36 - 0a18
14:46:36 - 024f00292a
14:46:36 - 42726f6164636f6d
14:46:36 - 025100242a
14:46:36 - 3132333400000000
14:46:36 - 025300232a
14:46:36 - 93b863805f9f9171
14:46:36 - 0f18
14:46:36 - 026300192a
14:46:36 - 01
Figure 5 Output of legattdb_dumpDb()
Practice with Hello Sensor Application
Complete the following two assignment to verify what you have learned from this session:
- Add a new characteristic to expose hello_sensor_timer_count in example application Hello Sensor.
- Add a Characteristic User Description Descriptor for characteristic HELLO_SENSOR_CONFIGURATION.
Overview
The NVRAM is used to store the data which may be modified frequently, such as pairing information and application private data, etc.
The storage space of NVRAM is the Volatile Section (VS) mentioned in document “WICED Smart BCM92073X EEPROM and SFLASH Layout”.
NVRAM Size and Record
The total size of NVRAM space is the length of VS. User can configure the VS’s location and size in the configuration file mentioned in document “WICED Smart BCM92073X EEPROM and SFLASH Layout”. The parameters are as follow:
- DLConfigVSLocation
VS start address in EEPROM or SFLASH.
- DLConfigVSLength
VS length.
Note: In WICES Smart SDK 2.1.0, the default VS length is 1024; In WICED Smart SDK 1.1.0, the length is 512.
The NVRAM is divided into many pages. The size of page is 32 bytes.
The BLE firmware occupy 4 pages, so the number of the pages left to store record item is
[Total Pages of Record Item] = ([VS Length] / 32) - 4
For example, when VS length is 1024, it has 32 pages, and 28 pages are used to save NVRAM record item.
A NVRAM record item has a 3 bytes header.
Page is the minimum allocation unit of NVRAM. It means that even if the record item’s size (included the header) is less than 32 bytes, it still needs to allocate one page for it. In other word, one record item occupies one page at least. Therefore, the maximum number of record items we can use is equal to total pages of record item as mentioned above.
The formula of allocated page number of a record item is as below:
[Allocated Page Number] = ([Record Item Data Size] + [Header Size] + 31) / 32
And the size of NVRAM occupied by a record item is as below:
[Record Item NVRAM Size] = [Allocated Page Number] * 32
The maximum length of record item data is 255.
NVRAM IDs
NVRAM record item is identified by ID. The valid rang for user is 0 – 0x6F. And in WICED Smart SDK, some IDs are used by stack and pre-defined applications as shown in Figure 1. We shouldn’t use these IDs.
File: Stacknvram.h (WICED-Smart-SDK\wiced-smart\bleapp\lestack\blecm) |
… #define STACKNVRAM_FIRST_USABLE_ITEM_NUMBER 0x00 // This item has the local root keys. #define STACKNVRAM_LOCAL_KEYS (STACKNVRAM_FIRST_USABLE_ITEM_NUMBER+1) // This item has the index table associated with the bonded devices. #define STACKNVRAM_BOND_INDEX (STACKNVRAM_LOCAL_KEYS + 1) // Note: This one should be the last one so that the idx can grow // to the end. We reserve 5 bonded device, defined in lesmpkeys.h #define STACKNVRAM_FIRST_BONDED_IDX (STACKNVRAM_BOND_INDEX + 1) #define VS_BLE_HOST_LIST 0x70 //0x70 is working // (STACKNVRAM_FIRST_BONDED_IDX + 1) #define VS_BLE_BPM_DATA (VS_BLE_HOST_LIST + 1) #define VS_BLE_HRM_DATA (VS_BLE_HOST_LIST + 1) #define VS_BLE_THER_DATA (VS_BLE_HOST_LIST + 1) #define VS_BLE_GEN_DATA (VS_BLE_HOST_LIST + 1) #define VS_BLE_WS_DATA (VS_BLE_HOST_LIST + 1) #define VS_BLE_GM_DATA (VS_BLE_HOST_LIST + 1) #define VS_BLE_BAT_DATA (VS_BLE_HOST_LIST - 1) #define VS_BLE_BAT_DATA1_1 (VS_BLE_HOST_LIST - 2) … |
Figure 1: Pre-defined NVRAM IDs
NVARM API
bleprofile_ReadNVRAM
- Description
Read a record item from NVRAM.
- Prototype
UINT8 bleprofile_ReadNVRAM(UINT8 vsID, UINT8 itemLength, UINT8* payload);
- Parameter
- vsID
The NVRAM ID of the record item.
- itemLength
The length of record item.
- payload
The buffer to be copied record item to.
- Return
- If success, return the number of bytes read from NVRAM, else return 0.
bleprofile_WriteNVRAM
- Description
Write a record item into NVARM.
- Prototype
UINT8 bleprofile_WriteNVRAM(UINT8 vsID, UINT8 itemLength, UINT8 *payload);
- Parameter
- vsID
The NVRAM ID of the record item.
- itemLength
The data length of record item.
- payload
The buffer of record item to be written into NVRAM.
- Return
- If success, return the number of bytes written into NVRAM, else return 0.
bleprofile_DeleteNVRAM
- Description
Delete a record item in NVRAM.
- Prototype
BOOL32 bleprofile_DeleteNVRAM(UINT8 vsID);
- Parameter
- vsID
The NVRAM ID of the record item.
- itemLength
The data length of record item.
- § payload
The buffer of record item to be written into NVRAM.
- Return
- If success, return 1, else return 0.
Table of Content
Overview
Preparing Firmware Image
Create Private and Public Keys
Add Related Source Files
Modify Source Codes
Build Application
SIGN SOTAFU Image
Section Layout Configuration
Section Change after Flash Download
Section Change after OTA Firmware Upgrade
OTA Upgrade Procedure
Upgrade Procedure
Control Point Command Format
Status Codes
Sample Codes in Central Side
Simple Introduction of Android Sample Codes
OTA Upgrade Procedure
This section describes the OTA upgrade procedure or protocol between central and peripheral.
Upgrade Procedure
In central’s view, the success procedure is as below:
1. Connects to peripheral.
2. Enable Handle Value Notification and Indication. (Figure 17.1)
- According to Bluetooth Specification (Core_V4.1, Volume 3, Part G, Clause 3.3.3.3), we need write value 0x0003 to descriptor UUID_DESCRIPTOR_CLIENT_CHARACTERISTIC_CONFIGURATION.
- Thus, in peripheral side, it can send the characteristic UUID_WS_SECURE_UPGRADE_CHARACTERISTIC_CONTROL_POINT’s Handle Value Notification and Indication to central to inform each command’s result.
3. Send [Prepare Download] command to peripheral, to inform it to do download preparation. (Figure 17.2)
- Write value [Prepare Download] to characteristic UUID_WS_SECURE_UPGRADE_CHARACTERISTIC_CONTROL_POINT. The format of command value, please refer to section Control Point Command Format.
- In peripheral, when received the command, it will enter “Ready For Download” state.
Note: According to the current reference application’s source codes in WICED Smart SDK, only when central receives both positive UUID_WS_SECURE_UPGRADE_CHARACTERISTIC_CONTROL_POINT’s Handle Value Notification and respond, we consider the operation as success
4. Get SOTAFU Image’s size, and Send [Download] command to peripheral with this size. (Figure 17.3)
- Write value [Download Command][Image Size] to characteristic UUID_WS_SECURE_UPGRADE_CHARACTERISTIC_CONTROL_POINT.
- In peripheral, when received the command, it will initialize the NVRAM location, calculate the patch size.
5. Read the first 4 bytes (version information) of SOTAFU Image, and send them to peripheral. (Figure 17.4)
- Write 4 bytes version information to characteristic UUID_WS_SECURE_UPGRADE_CHARACTERISTIC_DATA.
- In peripheral, after receive the version information of the OTA Image, it will check the version information as the rule mentioned before.
6. Continue to read N bytes Firmware Image Data from SOTAFU image, and send them to peripheral, until all of the Firmware Image Data are sent. (Figure 17.5)
- Write N bytes Firmware Image Data to characteristic UUID_WS_SECURE_UPGRADE_CHARACTERISTIC_DATA.
- In peripheral, it will write the received image data into NVRAM.
Note: In the reference application’s source codes, the maximum value of N is 20. According Bluetooth specification, the ATT protocol’s default ATT_MTU is 23 Bytes (Bluetooth Core Specification V4.1, Volume 3, Part G, Clause 5.2.1), and the Attribute Write Request PDU Header is 3 Bytes (Bluetooth Core Specification V4.1, Volume 3, Part F, Clause 3.4.5), so one LL (Link Layer) PDU’s maximum payload of Attribute Value is 20 Bytes.
7. Continue to read N bytes Signature Data from SOTAFU image, and send them to peripheral, until 128 Bytes Signature Data are sent. (Figure 17.6)
- Write N bytes Signature Data to characteristic UUID_WS_SECURE_UPGRADE_CHARACTERISTIC_DATA.
- In peripheral, it will save the signature data in RAM.
8. Send [Verify] command to peripheral, to inform it to do Signature Verification. (Figure 17.7)
- Write value [Verify Command] to characteristic UUID_WS_SECURE_UPGRADE_CHARACTERISTIC_CONTROL_POINT.
- In peripheral, it will verify the signature, and send the Handle Value Indication of Control Point to central. And after received the confirmation from central, it will set upgrade the firmware to a new one, then reset the device (Figure 17.8).
More detail procedure in peripheral, please refer the following function in “ws_sec_upgrade_ota.c (WICED-Smart-SDK\apps\ota_secure_firmware_upgrade)”:
- § int ws_upgrade_ota_handle_command(UINT8 *data, int len)
- § int ws_upgrade_ota_handle_data (UINT8 *data, int len)
Control Point Command Format
As mentioned above, central sends control command to peripheral by written characteristic UUID_WS_SECURE_UPGRADE_CHARACTERISTIC_CONTROL_POINT.
The value format is as below:
[Command Code (1 Byte)] [Parameter (0 – n bytes)]
The Command Code is defined in file “ws_sec_upgrade_ota.h” as shown in Figure 18.
File: ws_sec_upgrade_ota.h (WICED-Smart-SDK\Apps\ota_secure_firmware_upgrade) |
… #define WS_UPGRADE_COMMAND_PREPARE_DOWNLOAD 1 #define WS_UPGRADE_COMMAND_DOWNLOAD 2 #define WS_UPGRADE_COMMAND_VERIFY 3 #define WS_UPGRADE_COMMAND_FINISH 4 // not currently used #define WS_UPGRADE_COMMAND_GET_STATUS 5 // not currently used #define WS_UPGRADE_COMMAND_CLEAR_STATUS 6 // not currently used #define WS_UPGRADE_COMMAND_ABORT 7 … |
Figure 18: Command Codes of Control Point
Note: The parameter of command may be different between SOTAFU and OTAFU. And in different version WICED Smart SDK, it also may be different.
For SOTAFU, the main commands’ function and parameter is as follow:
- Prepare Download Command
- Inform peripheral to do prepare download, like initialize the state machine.
- No parameter.
- Download Command
- Inform peripheral the SOTAFU Image’s size.
- Parameter is SOTAFU’s total size (Include the version information and signature data), 2 Bytes.
- Verify Command
- After all SOTAFU Image is downloaded, inform peripheral to do verification.
- No parameter.
Status Codes
Status Code is the result of the command or writing data operation, returned from peripheral to central.
The status codes can be returned in the two cases as below:
- The respond of Write Characteristic (ex. Control Point, Data, etc.) Request.
- Handle Value Notification/Indication.
- Only for Control Point characteristic.
The Status Code is defined in file “ws_sec_upgrade_ota.h” as shown in Figure 19.
File: ws_sec_upgrade_ota.h (WICED-Smart-SDK\Apps\ota_secure_firmware_upgrade) |
… #define WS_UPGRADE_STATUS_OK 0 #define WS_UPGRADE_STATUS_UNSUPPORTED_COMMAND 1 #define WS_UPGRADE_STATUS_ILLEGAL_STATE 2 #define WS_UPGRADE_STATUS_VERIFICATION_FAILED 3 #define WS_UPGRADE_STATUS_INVALID_IMAGE 4 #define WS_UPGRADE_STATUS_INVALID_IMAGE_SIZE 5 #define WS_UPGRADE_STATUS_MORE_DATA 6 #define WS_UPGRADE_STATUS_INVALID_APPID 7 #define WS_UPGRADE_STATUS_INVALID_VERSION 8 #define WS_UPGRADE_WRITE_STATUS_SUCCESS 0x00 #define WS_UPGRADE_WRITE_STATUS_BAD_ID 0x81 #define WS_UPGRADE_WRITE_STATUS_BAD_MAJOR 0x82 #define WS_UPGRADE_WRITE_STATUS_TOO_MUCH_DATA 0x83 #define WS_UPGRADE_WRITE_STATUS_TOO_SHORT 0x84 #define WS_UPGRADE_WRITE_STATUS_ABORTED 0x85 … |
Figure 19: Status Codes
Sample Codes in Central Side
In WICES Smart SDK, it only provides a Windows sample codes in the central side under:
- WICED-Smart-SDK\Apps\ota_firmware_upgrade\peerapps\Windows\WsOtaUpgrade
- WICED-Smart-SDK\Apps\ota_secure_firmware_upgrade\peerapps\Windows\WsSecOtaUpgrade
Simple Introduction of Android Sample Codes
In Android, we also provide some sample codes, but in current, you need to commit a request in ours support website (support.broadcom.com) to get them.
There are two JAVA class:
- OtaUpgrader
- Abstract supper class.
- Define command data member and method.
- OtaSecureUpgrader
- OtaUpgrader’s sub-class.
- Implement all function of Secure OTA Firmware Upgrade.
The common methods are as shown in Figure 20:
- public OtaUpgrader(Context context);
- public OtaUpgrader(Context context, String deviceAddress, String patchFilePath, Callback callback);
- Constructor.
- We can specify the parameter in constructor or each separate method as below.
- public void setDeviceAddress(String deviceAddress);
- Set the Bluetooth address of the BLE device which wanted to do OTA Firmware Upgrade.
- In current design, it will connect to remote BLE device when do upgrading automatically, so it needs the device address.
- public void setPatchFilePath(String patchFilePath);
- Set the File path of patch (OTA Image).
- public void setCallback(Callback callback);
- Set the callback if we want to know the upgrading progress and result.
- Callback Interface is as below:
- public void onProgress(int realSize, int precent);
- Callback when each time when downloaded some data into remote device.
- public void onFinish(int status);
- Callback when the upgrading success or failed.
- public void onProgress(int realSize, int precent);
- public abstract void start();
- Start the OTA Firmware Upgrade.
- public abstract void stop ();
- Cancel the upgrading.
- public abstract int getPatchSize();
- Get the OTA Image size.
File: OtaUpgrader.java |
public abstract class OtaUpgrader { ... public static final int STATUS_OK = 0; ... public static final int COMMAND_PREPARE_DOWNLOAD = 1; ... public interface Callback { public void onProgress(int realSize, int precent); public void onFinish(int status); } … public OtaUpgrader(Context context) { … } public OtaUpgrader(Context context, String deviceAddress, String patchFilePath, Callback callback) { … } public void setDeviceAddress(String deviceAddress) { … } public void setPatchFilePath(String patchFilePath) { … } public void setCallback(Callback callback) { … } public abstract void start(); public abstract void stop(); public abstract int getPatchSize(); ... } |
Figure 20: OtaUpgrader Class
Like the source codes in peripheral, in class OtaSecureUpgrader, we also implement a state machine which can be easy to handle any cases.
A State class has common methods as shown in Figure 21:
- enter()
- When enter the state, this method will be called.
- exit()
- When exit the state, this method will be called.
- handleEvent() / processEvent()
- After entered the state, it will call handleEvent() to handle each received event first. The method handleEvent() handles some common events, and calls processEvent() to handle others. If a state only cares some events, it can handle these event in processEvent().
File: OtaSecureUpgrader.java |
public class OtaSecureUpgrader extends OtaUpgrader { ... private final class StateMachine extends Handler { ... private class State { … public void enter() { … } public void exit() { … } public boolean processEvent(int event, int status) { … } public void handleEvent(State destState, int event, int status) { … } } … } } |
Figure 21: Method of State Class
The methods of StateMachine class are as shown in Figure 22:
- start()
- Start the state machine
- stop()
- Abort the current state, force it transfer to finish state.
- transitionTo()
- Transition to another State.
- postEvent()
- Post the received events to current State to handle it.
- quit()
- Quit the state machine, the state machine will be died.
File: OtaSecureUpgrader.java |
public class OtaSecureUpgrader extends OtaUpgrader { ... private final class StateMachine extends Handler { … public void start() { … } public void stop() { … } public void quit() { … }
public void postEvent(int event, int status) { … } … private void transitionTo(State destState, int status) { … } … } } |
Figure 22: Method of StateMachine Class
All of states and transition between states of OtaSecureUpgrader are as shown in Figure 23.
Notice:
1. Sample code OTA_Android_Sample_NoSecure.zip is only tested in WICED Smart SDK 1.1.0.
2. Sample code AndroidOtaSampleCodes_V1.0.zip is tested in WICED Smart SDK 1.1.0 and 2.1.0.
3.Sample code AndroidOtaSampleCodes_V1.1.zip is tested in WICED Smart SDK 1.1.0 and 2.1.0.