@PJ_Glasso , it seems I cannot edit my post after a certain period.
Just an amendment: in each round of transmission the peripheral transmits alternatively on ch37, 38, 39 the same advertising packet. So actually total 30 identical packets are transmitted over the 1s interval in MJ’s example.
I think, I didn’t explained well my project. Let say, I want to record temperature. Each hour, the board record a temperature and store it internally (in the QSPI Flash memory). One or two times a year, I will visit the logger on field. I will transfer data from the logger to a smartphone. So most of the time, the logger don’t transmit data. It is just waiting for a connexion. Once the connexion is established, I don’t care too much on power consumption (although it should not drain the battery in one minute). So, how can I set some kind of “wait for connexion” with a low power consumption?
Eric_S,
The easiest way would be to connect a switch to the board and wake it up with a switch interrupt to initiate the connection. Or the board should advertise periodically regardless of whether Central is around or not.
To my knowledge, I can’t think of a way to wake up a board that is sleeping from central.
If anyone has a better idea, please advise.
msfujino,
I first implemented the switch solution, on adafruit boards at that time but stopped development due to high power consumption. Now, with the XIAO board, I can do the same. But I would also like to avoid the switch. So advertising each minute all the time and, if a Central active is present, the Central may take the opportunity to establish a connexion after catching an advertising packet.
As XIAO advertises every minute, current consumption increases, is this acceptable? To reduce current consumption, it would be better to reduce the number of advertisements per minute.
Hi hobbya,
Most excellent explanations , Most like me are familiar with only the basic scan and connect , I like the other options though too. Reminds me of UDP a connectionless protocol Vs. TCP .
Passive scanning (broadcasting a status)and the ability to make a connection to a specific peripheral when needed. Would be the optimum for my application, that would also give me access to more numbers of peripheral’s. I might be showing my age but this BLE acts like CDMA connection kind of LOL.
You point out the main concern about missing an alarm (motion alarm) in my case the Peripheral currently has a read /notify connection if the alarm flag changes it’s almost instantons. You already see the problem (you have to be connected) with this Nicer Passive and Active scanning with data approach allot more flexibility maybe on multiple devices.
Wow, lots to ingest here but Steller work for sure, I’m stoked to try and implement this technique I wonder if you can switch modes is possible? and thank you for responding and sharing of this great knowledge.
GL PJ
I am also a hobbyist like you. I learn something new daily through reading.
If the scanner always performs scanning and does not sleep, the chance to miss the advertising packet is really small unless there is heavy interference in the 2.4GHz band. If a peripheral advertises sufficiently long its packets should reach the scanner. A trial is needed to determine the advertising interval (hence power consumption) in the actual environment so that one can select an appropriate battery for the peripheral.
@msfujino
regarding the peripheral number, you may define it as DEC instead of HEX. This number will never exceed 1 byte. To retrieve the value at the central, just read the appropriate byte instead of working on 2 bytes.
The reason for reserving two bytes for Peripheral number is that I wanted to put the identification number in the upper one byte in case the experimental CID = 0xFFFF duplicates with other experimental devices.
I am currently experimenting with using scan response to increase the amount of data that can be transferred. I am reading the bluefruit library very hard but am struggling. Do you have any tips on how to do this?
@msfujino
What if we do it in another way:
- advertise data set 1 for 1s
- clear data
- advertise data set 2 for another 1s
- delay 10s (sleep)
Theoretically, scan response may be a more power saving approach since it broadcasts only on that particular channel the request is received. Advertising however always broadcasts on 3 channels.
Yet to my earlier experiment, the central capture rate of scan response was only 5% (peripheral 100% duty) but the capture rate of advertising was at least 5/30 or 17% (peripheral 10% duty).
I do not have a shielded environment to isolate from other devices in the vicinity. So I am unable to tell what has caused the bad scan response performance. Whether it is due to too many irrelevant devices making scan requests or the library itself I can hardly tell.
hobbya,
I think the idea of sending the data set twice would work if we implement the code. I am currently working on a way to send the data in a scan response for comparison.
The following directory has an example of sending local names in a scan response. Peripheral puts the local name in the scan response packet, but Central is not able to retrieve it properly. I am in the process of trying to figure out if the cause is wrong code or if the functionality is not implemented. I still need more time.
\Arduino15\packages\Seeeduino\hardware\nrf52\1.1.1\libraries\Bluefruit52Lib\examples\Projects\rssi_proximity
Previously I used the central_scan_advanced example for the scan response. It would not work until I disabled the scanner filter. I did not investigate further due to the code complexity.
Still have not figured out the reason. Attached is my sketch.
The advertising and scan response packets could be properly received by the Nordic mobile app. However the central only picked up one scan response over 3 minutes with the MSD filter disabled. It would not pick up any scan response if the filter was enabled.
NRF52840_Scan_Response.zip (3.9 KB)
Hi hobbya, I will try your sketch from now on.
Here are my findings for today.
To make it easier to distinguish, two data data1 and data2 were defined and sent on the advertise and scan response. When checked by the mobile app, 55 bytes were received, including 2 bytes of CID. However, XIAO Central could only receive data1 on the advertise. The conclusion is that there is a problem with Central.
uint8_t data1[] = { 0xFF, 0xFF, // CID 2
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, // data 24
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20,
0x21, 0x22, 0x23, 0x24};
uint8_t data2[] = { 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xB0, // data 29
0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xC0,
0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9};
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
Bluefruit.Advertising.setType(BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED);
Bluefruit.Advertising.addData(BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA, data1, sizeof(data1));
Bluefruit.Advertising.addTxPower();
Bluefruit.ScanResponse.addData(BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA, data2, sizeof(data2));
Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setIntervalMS(100, 100); // fast mode 100mS, slow mode 100mS
Bluefruit.Advertising.setFastTimeout(1); // fast mode 1 sec
Bluefruit.Advertising.start(1); // stop advertising after 1 sec, fast 1 sec slow 0 sec
So I read ble_gap.h and found the area of concern. I will continue to investigate a little further.
l\Arduino15\packages\Seeeduino\hardware\nrf52\1.1.1\cores\nRF5\nordic\softdevice\s140_nrf52_7.3.0_API\include\ble_gap.h:709 and 1278
/**@brief Advertising report type. */
typedef struct
{
uint16_t connectable : 1; /**< Connectable advertising event type. */
uint16_t scannable : 1; /**< Scannable advertising event type. */
uint16_t directed : 1; /**< Directed advertising event type. */
uint16_t scan_response : 1; /**< Received a scan response. */
uint16_t extended_pdu : 1; /**< Received an extended advertising set. */
uint16_t status : 2; /**< Data status. See @ref BLE_GAP_ADV_DATA_STATUS. */
uint16_t reserved : 9; /**< Reserved for future use. */
} ble_gap_adv_report_type_t;
/**@brief Event structure for @ref BLE_GAP_EVT_ADV_REPORT.
*
* @note If @ref ble_gap_adv_report_type_t::status is set to @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA,
* not all fields in the advertising report may be available.
*
* @note When ble_gap_adv_report_type_t::status is not set to @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA,
* scanning will be paused. To continue scanning, call @ref sd_ble_gap_scan_start.
*/
typedef struct
{
ble_gap_adv_report_type_t type; /**< Advertising report type. See @ref ble_gap_adv_report_type_t. */
ble_gap_addr_t peer_addr; /**< Bluetooth address of the peer device. If the peer_addr is resolved:
@ref ble_gap_addr_t::addr_id_peer is set to 1 and the address is the
peer's identity address. */
ble_gap_addr_t direct_addr; /**< Contains the target address of the advertising event if
@ref ble_gap_adv_report_type_t::directed is set to 1. If the
SoftDevice was able to resolve the address,
@ref ble_gap_addr_t::addr_id_peer is set to 1 and the direct_addr
contains the local identity address. If the target address of the
advertising event is @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE,
and the SoftDevice was unable to resolve it, the application may try
to resolve this address to find out if the advertising event was
directed to us. */
uint8_t primary_phy; /**< Indicates the PHY on which the primary advertising packet was received.
See @ref BLE_GAP_PHYS. */
uint8_t secondary_phy; /**< Indicates the PHY on which the secondary advertising packet was received.
See @ref BLE_GAP_PHYS. This field is set to @ref BLE_GAP_PHY_NOT_SET if no packets
were received on a secondary advertising channel. */
int8_t tx_power; /**< TX Power reported by the advertiser in the last packet header received.
This field is set to @ref BLE_GAP_POWER_LEVEL_INVALID if the
last received packet did not contain the Tx Power field.
@note TX Power is only included in extended advertising packets. */
int8_t rssi; /**< Received Signal Strength Indication in dBm of the last packet received.
@note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature measurement. */
uint8_t ch_index; /**< Channel Index on which the last advertising packet is received (0-39). */
uint8_t set_id; /**< Set ID of the received advertising data. Set ID is not present
if set to @ref BLE_GAP_ADV_REPORT_SET_ID_NOT_AVAILABLE. */
uint16_t data_id:12; /**< The advertising data ID of the received advertising data. Data ID
is not present if @ref ble_gap_evt_adv_report_t::set_id is set to
@ref BLE_GAP_ADV_REPORT_SET_ID_NOT_AVAILABLE. */
ble_data_t data; /**< Received advertising or scan response data. If
@ref ble_gap_adv_report_type_t::status is not set to
@ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA, the data buffer provided
in @ref sd_ble_gap_scan_start is now released. */
ble_gap_aux_pointer_t aux_pointer; /**< The offset and PHY of the next advertising packet in this extended advertising
event. @note This field is only set if @ref ble_gap_adv_report_type_t::status
is set to @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA. */
} ble_gap_evt_adv_report_t;
Your approach for the peripheral is the same as my sketch. Indeed the central has problems catching the scan response, even though it can recognize the packet as scannable.
/* Display the timestamp and device address */
if (report->type.scan_response)
//if (report->type.scannable)
{
Serial.printf("[SR%10d] Packet received from ", millis());
}
It can print “SR” if I set the type to scannable, which means it recognizes the incoming packet.
The principle of the code is simple, it prints out the report whenever there is a callback. The reports of advertising and scan response shall come up alternatively but as you said the latter does not show up at all.
Some more observations:
Case 1:
Central => my sketch above without MSD filter
Peripheral => adafruit beacon example
Sniffer: peripheral sent out quite a lot of scan responses to central
Central serial: captured a lot less scan responses compared to above
Case 2:
Central => my sketch above with MSD filter
Peripheral => my sketch above but advertising data was reduced to a flag only
void startAdv(void)
{
// Set Flag for discovery mode, optional
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE);// Construction of data packet to be advertising
if (counter == 0xFF)
{counter = 0;}
else
{counter = counter + 1;}
user_data[0] = 0x59; // little endian format for first and second entry
user_data[1] = 0x00; // (00-59) means Nordic Semi
user_data[2] = counter; // third entry increments with each advertising cycle
Bluefruit.Advertising.addData(BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA, user_data, sizeof(user_data)/sizeof(user_data[0]));
Bluefruit.Advertising.clearData();// Construction of scan response
scan_rsp_data[0] = 0x59; // little endian format for first and second entry
scan_rsp_data[1] = 0x00; // (00-59) means Nordic Semi
scan_rsp_data[2] = 0xD1;
scan_rsp_data[3] = 0xD2;
scan_rsp_data[4] = 0xD3;
scan_rsp_data[5] = 0xD4;
Bluefruit.ScanResponse.addData(BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA, scan_rsp_data, sizeof(scan_rsp_data)/sizeof(scan_rsp_data[0]));Bluefruit.Advertising.setType(BLE_GAP_ADV_TYPE_NONCONNECTABLE_SCANNABLE_UNDIRECTED);
//Bluefruit.Advertising.setType(BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED);
Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setIntervalMS(100, 100); // in unit of ms
Bluefruit.Advertising.setFastTimeout(5); // number of seconds in fast mode
Bluefruit.Advertising.start(5); // stop advertising after 5 seconds
}
Central serial: captured a lot of scan responses
I am wondering if central is not fast enough to catch and decode both the advertising and scan response packets in a short time. I will try to adjust the 2 payload sizes or to increase the serial buffer next time. I have spent too much time on this and my wife is not happy.
Next, I plan to experiment with enclosing Peripheral and Central in an empty cookie can, isolated from the surrounding BLE.
“Scan Response” gets a bit away from the purpose of “System ON Sleep” in this thread, so it might be better to start a new thread on “Scan Response”. I am also thinking of posting this on the following github with issues.
‘GitHub - adafruit/Adafruit_nRF52_Arduino: Adafruit code for the Nordic nRF52 BLE SoC on Arduino’
Have a nice weekend with your wife.
Yes we should post somewhere for this topic.
Wife is still alseep. Try this, seems to work if we do something basic.
NRF52840_MSD.zip (3.1 KB)
I just checked. It is working fine.
I will study what is different from the previous sketches.
I will also continue to experiment with how far the data length can be increased and what the current consumption will be.
For the benefit of other users, I would appreciate if you could post something about ScanResponse.