arduino-libraries / ArduinoBLE

ArduinoBLE library for Arduino
GNU Lesser General Public License v2.1
311 stars 205 forks source link

Is there a way to get the Advertising Packets Count (for Eddystone TLM) #83

Closed Gerriko closed 4 years ago

Gerriko commented 4 years ago

I am working on an Eddystone example which transmits both UID and TLM data packets.

I have my Arduino example working now (SEE CODE below. This is based on a code mode I had to make for the ArduinoBLE library: see https://github.com/arduino-libraries/ArduinoBLE/issues/82)

The issue now is that I cannot find a way to get or read the Advertising packets count, which is required for the Eddystone TLM packet format.

Is there anyway of doing this?

I am having to estimate this based on the default advertising interval.

`/* Eddystone Beacon UID and TLM Example

This example creates a BLE beacon using the Eddystone format.

The circuit: Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.

This example code is in the public domain. */

/****

include

// Standard Eddystone Flags

define FLAGS_UID (0x00u)

define FLAGS_URL (0x10u)

define FLAGS_TLM (0x20u)

// The preconfigured TX power levels

define PWR_LVL_3_DBM (0x03) / 3 dBm /

define PWR_LVL_0_DBM (0x00) / 0 dBm /

define PWR_LVL_NEG_6_DBM (0xFA) / -6 dBm /

define PWR_LVL_NEG_18_DBM (0xEE) / -18 dBm /

define MAX_ADVERTISING_PACKET_SIZE (31u)

define MAX_UID_PACKET_SIZE (20u)

define MAX_TLM_PACKET_SIZE (14u)

/ Eddystone packet index of the UID service data /

define EDDY_SERVICE_INDEX (00u)

/ Eddystone packet index of the name space ID /

define NAME_SPACE_INDEX (2u) //2

/ Eddystone packet index of the instance ID /

define INSTANCE_INDEX (12u) //12

/ Eddystone packet indexes of the reserved fields /

define RFU_INDEX_0 (18u)

define RFU_INDEX_1 (19u)

/ Data written to reserved Eddystone fields /

define RFU_DEFLT_VALUE (0u)

/ UID Service data for the UID frame /
const uint8_t UID_SERVICE_DATA[2] = { FLAGS_UID, / Signifies Eddystone UID /\ PWR_LVL_NEG_18_DBM / TX Ranging data: -6dB/
};

// UID Data - split between Namespace ID (10) and Instance ID (6) const uint8_t UID_NAMESPACEDATA[10] = { / Namespace ID / 0xCB, // NID[0] 0x6F, // NID[1] 0x15, // NID[2] 0xCE, // NID[3] 0x20, // NID[4] 0x2A, // NID[5] 0xCE, // NID[6] 0x15, // NID[7] 0x6F, // NID[8] 0xCB // NID[9] };

const uint8_t UID_INSTANCEDATA[6] = { / Instance ID / 0x01, // IID[0] 0x02, // IID[1] 0x03, // IID[2] 0x04, // IID[3] 0x05, // IID[4] 0x06 // IID[5] };

/ TLM Service data for the TLM frame /
const uint8_t TLM_SERVICE_DATA[2] = { FLAGS_TLM, / Signifies Eddystone TLM /\ 0 / This is the TLM version number - value is set at 0/
};

const uint32_t UID_TIMEINTERVAL = 14000; // 14 seconds const uint32_t TLM_TIMEINTERVAL = 1000; // 1 second

// BLE Eddystone Broadcasting Service BLEService EddystoneService("FEAA");

// BLE Eddystone Broadcasting Characteristic BLECharacteristic EddystoneChar("FEAB", // standard 16-bit characteristic UUID for Eddystone Beacons BLERead | BLEBroadcast, MAX_ADVERTISING_PACKET_SIZE, true); // this allows for both connecting and listening to advertisements

uint32_t t_PowerUp = 0; uint32_t t_BeaconInt = 0;

uint16_t t_BLEadvertisingInterval = 160;

uint8_t AdvertisementData[MAX_ADVERTISING_PACKET_SIZE];

bool TLM_Mode = false;

uint16_t updateBatteryLevel() { / Read the current voltage level on the A0 analog input pin. This is used here to simulate the charge level of a battery. / int battery = analogRead(A0);

// The battery voltage is measured in milliVolts (we assume max voltage is 3V3 uint16_t batteryLevel = map(battery, 0, 1023, 0, 3300); return batteryLevel; }

// Eddystone UID configuration void ConfigureEddystoneUIDServiceData() {

memset(AdvertisementData, 0x00, MAX_ADVERTISING_PACKET_SIZE);

memcpy (&AdvertisementData[EDDY_SERVICE_INDEX], &UID_SERVICE_DATA, sizeof(UID_SERVICE_DATA)); / Load Name-space ID / memcpy (&AdvertisementData[NAME_SPACE_INDEX], &UID_NAMESPACEDATA, sizeof(UID_NAMESPACEDATA)); / Load Instance ID / memcpy (&AdvertisementData[INSTANCE_INDEX], &UID_INSTANCEDATA, sizeof(UID_INSTANCEDATA)); / Load the reserved fields with default values / AdvertisementData[RFU_INDEX_0] = RFU_DEFLT_VALUE;
AdvertisementData[RFU_INDEX_1] = RFU_DEFLT_VALUE;

}

void ConfigureEddystoneTLMServiceData(uint32_t PowerUpTime) {

memset(AdvertisementData, 0x00, MAX_ADVERTISING_PACKET_SIZE);

memcpy (&AdvertisementData[EDDY_SERVICE_INDEX], &TLM_SERVICE_DATA, sizeof(TLM_SERVICE_DATA));

/ Load Battery Voltages / uint16_t currentBatteryVoltage = updateBatteryLevel(); AdvertisementData[2] = (uint8_t)((currentBatteryVoltage >> 8) & 0xFF);
AdvertisementData[3] = (uint8_t)(currentBatteryVoltage & 0xFF);
// WHen Battery Voltage is not available //AdvertisementData[2] = 0x00;
//AdvertisementData[3] = 0x00;

/ Load Internal Temperature / // Beacon temperature in Celsius (8.8 fixed point notation): // https://courses.cit.cornell.edu/ee476/Math/ //currentTemperature = GetMeasuredTemprature(); //AdvertisementData[4] = (uint8_t)((currentTemperature >> 8) & 0xFF); //AdvertisementData[5] = (uint8_t)(currentTemperature & 0xFF); // When Temperature values not available AdvertisementData[4] = 0x80; AdvertisementData[5] = 0x00;

// Advertising PDU count since power-up or reboot (estimating based on default advertising interval) uint32_t currentAdvPacketCount = PowerUpTime/t_BLEadvertisingInterval;

/ Eddystone TLM packet indexes for packets transmitted /
AdvertisementData[6] = (uint8_t)((currentAdvPacketCount >> 24) & 0xFF); AdvertisementData[7] = (uint8_t)((currentAdvPacketCount >> 16) & 0xFF); AdvertisementData[8] = (uint8_t)((currentAdvPacketCount >> 8) & 0xFF); AdvertisementData[9] = (uint8_t)((currentAdvPacketCount) & 0xFF);

/ Eddystone TLM power up time in seconds / PowerUpTime /= 1000; AdvertisementData[10] = (uint8_t)((PowerUpTime >> 24) & 0xFF); AdvertisementData[11] = (uint8_t)((PowerUpTime >> 16) & 0xFF); AdvertisementData[12] = (uint8_t)((PowerUpTime >> 8) & 0xFF); AdvertisementData[13] = (uint8_t)((PowerUpTime) & 0xFF); }

void setup() { Serial.begin( 9600 ); while (!Serial);

// begin BLE initialization if (!BLE.begin()) { Serial.println("starting BLE failed!"); while (1); }

t_PowerUp = millis(); // This is when we measure the power up period from

Serial.println(F("Eddystone UID Beacon Example"));

BLE.setConnectable(false); BLE.setDeviceName("EddyBea");

BLE.setAdvertisedService(EddystoneService); // add the service UUID Serial.print("Broadcast confirmed: "); Serial.println((EddystoneChar.broadcast()?"Yes":"No")); BLE.addService(EddystoneService); // Add the eddystone service EddystoneService.addCharacteristic(EddystoneChar); // add the eddystone characteristic

ConfigureEddystoneUIDServiceData(); t_BeaconInt = millis(); EddystoneChar.writeValue(AdvertisementData, MAX_UID_PACKET_SIZE); // set initial value for this characteristic BLE.advertise();

}

void loop() { if (TLM_Mode) { if ((millis() - t_BeaconInt) > TLM_TIMEINTERVAL) { BLE.stopAdvertise();
Serial.println("Switching to UID Mode"); ConfigureEddystoneUIDServiceData(); t_BeaconInt = millis(); EddystoneChar.writeValue(AdvertisementData, MAX_UID_PACKET_SIZE); // set initial value for this characteristic BLE.advertise(); TLM_Mode = false; }
} else { // UID Mode if ((millis() - t_BeaconInt) > UID_TIMEINTERVAL) { BLE.stopAdvertise();
Serial.println("Switching to TLM Mode"); uint32_t PwrUpTime = millis() - t_PowerUp; ConfigureEddystoneTLMServiceData(PwrUpTime); t_BeaconInt = millis(); EddystoneChar.writeValue(AdvertisementData, MAX_TLM_PACKET_SIZE); // set initial value for this characteristic BLE.advertise(); TLM_Mode = true; } } BLE.poll(); } `

polldo commented 4 years ago

Hi @Gerriko , at the moment we don't support such functionality. However the way you are handling this seems good to me.